¿Cómo unir cadenas en Elixir?

158

¿Cómo unir dos cadenas en una lista con un espacio, como:

["StringA", "StringB"]

se convierte

"StringA StringB"
tiagofm
fuente

Respuestas:

220

Si solo quieres unirte a alguna lista arbitraria:

"StringA" <> " " <> "StringB"

o simplemente use la interpolación de cadenas:

 "#{a} #{b}"

Si el tamaño de su lista es arbitrario:

Enum.join(["StringA", "StringB"], " ")

... todas las soluciones anteriores volverán

"StringA StringB"
tiagofm
fuente
36
La sintaxis alternativa con el operador de canalización: ["StringA", "StringB"] |> Enum.join " "
Ryan Cromwell
11
Debe evitar el operador de la tubería cuando en realidad no tiene necesidad de canalizar las operaciones.
Carlos
3
@EdMelo Care para explicar por qué. Técnicamente, nunca se "necesita" realmente para canalizar operaciones, ya que se podría lograr el mismo comportamiento anidando llamadas a funciones.
Schrockwell
8
@Schrockwell sí, "debería" era demasiado. Lo que quiero decir es que este caso no tiene ganancia en la legibilidad, por lo que una llamada de función simple haría pensar más explícitamente.
Carlos
3
Debe utilizar la mayor cantidad de lenguaje Elixir que pueda para demostrar a los empleadores potenciales que lo sabe. Así que usaría todas las soluciones anteriores en el mismo archivo.
rodmclaughlin
61

Si lo que tiene es una lista arbitraria, puede usarla Enum.join, pero si es solo para dos o tres, la concatenación explícita de cadenas debería ser más fácil de leer

"StringA" <> " " <> "StringB"

Sin embargo, a menudo no necesita tenerlo como una sola cadena en la memoria si va a generarlo, por ejemplo, a través de la red. En ese caso, puede ser ventajoso usar una iolist (un tipo específico de una lista profunda), que le ahorra copiar datos. Por ejemplo,

iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok

Dado que tendría esas cadenas como variables en alguna parte, al usar una lista profunda, evita asignar una cadena completamente nueva solo para generarla en otro lugar. Muchas funciones en elixir / erlang entienden las iolistas, por lo que a menudo no necesitaría hacer el trabajo adicional.

Carlos Martín Nieto
fuente
Si necesita agregar algo al final de un comando de tubería "String" |> (& (& 1 <> "\ n")). ()
hwatkins
9

Respondiendo para completar, también puede usar la interpolación de cadenas :

iex(1)> [a, b] = ["StringA", "StringB"]
iex(2)> "#{a} #{b}"
"StringA StringB"
Sheharyar
fuente
5

Si estuvo de acuerdo con agregar un espacio en su lista, podría tratarlo como una lista:

["StringA", " ", "StringB"] |> IO.iodata_to_binary # "StringA StringB"

Esto le da algunos aumentos de rendimiento ya que no está duplicando ninguna de las cadenas en la memoria.

Uri
fuente
4

Un Enum.reduce también funcionaría para su ejemplo, ¿no?

iex(4)> Enum.reduce(["StringA", "StringB"], fn(x, acc) -> x <> " " <> acc end) "StringB StringA"

Low Kian Seong
fuente
Sí, pero necesita una reducción inversa Enum.reduce (["a", "b", "c"] |> Enum.reverse, fn (x, acc) -> x <> "" <> acc end) "ab c "
Andrei Sura
personalmente creo que esta es la mejor respuesta porque se generaliza a otros casos en los que se puede utilizar reducir Habla sobre la idea de "do.call" en R.
Thomas Browne
3

Depende de lo que intentes hacer. Si solo está tratando de escribir en una nueva variable, simplemente use:

  • Interpolación de cuerdas

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
  • Concatenación de cadenas: "StringA" <> " " <> "StringB

  • Enum.join(): ["StringA", "StringB"] |> Enum.join(" ")

Sin embargo, como mencionó Uri, las LIO también se pueden usar:

["StringA", " ", "StringB"] |> IO.iodata_to_binary

Los IOListas realmente serán los más eficaces si necesita preocuparse por el consumo de recursos. Big Nerd Ranch tiene una buena reseña sobre las ganancias de rendimiento con IOLists.

Jason Steinhauser
fuente
2

Hay varios métodos, pero saber cómo maneja los valores nulos puede determinar qué método debe elegir.

Esto arrojará un error

iex(4)> "my name is " <> "adam"
"my name is adam"

iex(1)> "my name is " <> nil
** (ArgumentError) expected binary argument in <> operator but got: nil
    (elixir) lib/kernel.ex:1767: Kernel.wrap_concatenation/3
    (elixir) lib/kernel.ex:1758: Kernel.extract_concatenations/2
    (elixir) lib/kernel.ex:1754: Kernel.extract_concatenations/2
    (elixir) expanding macro: Kernel.<>/2
    iex:1: (file)

Esto solo insertará una cadena "" en blanco:

iex(1)> "my name is #{nil}"
"my name is "

Como será esto:

iex(3)> Enum.join(["my name is", nil], " ")
"my name is "

Considere también los tipos. Contigo <>no obtienes ningún casting gratis:

iex(5)> "my name is " <> 1
** (ArgumentError) expected binary argument in <> operator but got: 1
    (elixir) lib/kernel.ex:1767: Kernel.wrap_concatenation/3
    (elixir) lib/kernel.ex:1758: Kernel.extract_concatenations/2
    (elixir) lib/kernel.ex:1754: Kernel.extract_concatenations/2
    (elixir) expanding macro: Kernel.<>/2
    iex:5: (file)

iex(5)> "my name is #{1}"
"my name is 1"

iex(7)> Enum.join(["my name is", 1], " ")
"my name is 1"

El rendimiento en la práctica parece más o menos el mismo:

iex(22)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{8023855, :ok}
iex(23)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{8528052, :ok}
iex(24)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{7778532, :ok}
iex(25)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7620582, :ok}
iex(26)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7782710, :ok}
iex(27)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7743727, :ok}

Entonces, realmente depende de si desea bloquearse o no cuando los valores interpolados son nilo del tipo incorrecto.

atomkirk
fuente
0

También podrías hacer 'string A' ++ ' ' ++ 'string B'

Vatsala
fuente
77
¿No se convertirán en char-list?
Virtual
0

Considere usar una Lista de E / S, si tiene ["Cadena1", "cadena2"] y usa iolist_to_binary / 1, copiará esas cadenas en una nueva cadena. Si tiene una lista de E / S, puede generarla en la mayoría de los casos y la concatenará en el puerto. Y esta es la clave, el tiempo de ejecución no necesitará hacer copias de los datos, por lo que es mucho más eficiente que la concatenación.

Zachary K
fuente