Cuaderno de GNUtas

La expresión Elisp mapconcat: ejemplos de uso y un caso práctico

La expresión mapconcat aplica una función determinada sobre todos y cada uno de los elementos de una lista, y nos devuelve el resultado como una cadena de texto. El primer argumento de mapconcat es la función que queremos aplicar; el segundo, la lista sobre la que vamos a aplicarla; el tercero, el separador que han de tener los elementos de la lista cuando pasen a ser cadena de texto.

El escenario más básico de uso es cuando queremos, simplemente, convertir una lista en cadena de texto. Para ello, nos bastaría con emplear una función que devolviese el argumento que toma (el elemento sobre el que se aplica) tal cual, como identity. Así, si tenemos la lista ("Fulano" "Mengano" "Zutano"), podemos ensayar lo siguiente:

(message
 (mapconcat 'identity '("Fulano" "Mengano" "Zutano") " "))

mapconcat aplica la función identity sobre cada elemento de la lista y devuelve el propio elemento. Recordemos que la lista ha de llevar un quote (un apóstrofe) para que no sea evaluado ninguno de sus elementos. El espaciador entre elementos es un espacio simple. Todo eso se recoge en un mensaje al minibúfer. Si evaluamos la expresión, obtendremos:

"Fulano Mengano Zutano"

Otro ejemplo. Aquí la función a aplicar puede ser una simple función anónima (expresión lambda) y el espaciador unos puntos suspensivos seguidos de espacio simple:

(message
 (mapconcat (lambda (elemento)
	    (format "Hola, %s" elemento))
		'("Fulano" "Mengano" "Zutano")
			 "... "))

Si evaluamos esto, obtendremos entonces como mensaje:

"Hola, Fulano... Hola, Mengano... Hola, Zutano"

Podemos complicarlo más, y hacer que la función anónima aplique una sustitución (la letra «o» reemplazada por «xxx»):

(message
 (mapconcat
    (lambda (elemento)
    (replace-regexp-in-string "o" "xxx" elemento))
       '("Fulano" "Mengano" "Zutano")
	     "... "))

Si lo evaluamos, obtenemos ahora:

"Fulanxxx... menganxxx... zutanxxx"

Un caso práctico

Queremos definir una función que nos haga lo siguiente:

  1. Toma los (nombres de) archivos marcados en el navegador de archivos Dired y hace una lista con ellos;
  2. esa lista pasa a cadena de texto, y
  3. la cadena de texto resultante se aplica como argumento de algún comando de shell.

Concretando más: queremos fusionar los archivos PDF que tengamos marcados en Dired en un único PDF, y para ello usaremos el programa pdfjam, incluido en TeX Live, de esta forma:

pdfjam archivo1.pdf archivo2.pdf archivo3.pdf -o archivo-resultante.pdf

Para conseguir eso, podemos ensayar esta función:

(defun fusiona-pdf ()
"fusiona en un único PDF varios PDF marcados en Dired, usando el programa pdfjam"
  (interactive)
  (let
      ((archivo (read-string "¿nombre del archivo de salida (sin extensión)?"))
       (pdf-lista (mapconcat 'identity (dired-get-marked-files) " "))) ;; esto convierte una lista en cadena de texto
    (shell-command (format "pdfjam %s -o %s.pdf" pdf-lista archivo))))

Nuestra función es muy simple, pero resultona. Consta de una expresión let donde a la variable archivo se asigna como valor el nombre del PDF resultante, que debemos escribir (sin extensión) cuando se nos pregunte por ello. La variable pdf-lista toma la lista de archivos marcados en Dired (nuestros PDF a fusionar) y la pasa a cadena de texto de la misma forma que vimos en nuestro primer ejemplo. La lista de PDF se obtiene con dired-get-marked-files:

variable valor
pdf-lista (mapconcat 'identity (dired-get-marked-files) " ")

Y, finalmente, en el cuerpo de la expresión let lanzamos el comando pdfjam con las dos variables formadas según lo necesario.

Publicado: 24/07/2019

Última actualización: 24/07/2019


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs