Wie verbinde ich Strings in Elixir?

158

Wie verbinde ich zwei Zeichenfolgen in einer Liste mit einem Leerzeichen wie:

["StringA", "StringB"]

wird

"StringA StringB"
thiagofm
quelle

Antworten:

220

Wenn Sie sich nur einer beliebigen Liste anschließen möchten:

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

oder verwenden Sie einfach die String-Interpolation:

 "#{a} #{b}"

Wenn Ihre Listengröße beliebig ist:

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

... alle oben genannten Lösungen werden zurückkehren

"StringA StringB"
thiagofm
quelle
36
Die alternative Syntax unter Verwendung des Pipeline-Operators: ["StringA", "StringB"] |> Enum.join " "
Ryan Cromwell
11
Sie sollten den Pipeline-Operator meiden, wenn Sie keine Pipe-Operationen benötigen.
Carlos
3
@EdMelo Möchten Sie näher erläutern, warum? Technisch gesehen "brauchen" Sie Pipe-Operationen nie wirklich, da das gleiche Verhalten durch Verschachteln von Funktionsaufrufen erzielt werden kann.
Schrockwell
8
@Schrockwell ja, "sollte" war zu viel. Was ich meine ist, dass Sie in diesem Fall keinen Gewinn an Lesbarkeit haben, so dass ein einfacher Funktionsaufruf das Denken expliziter machen würde.
Carlos
3
Sie sollten so viel wie möglich von der Elixir-Sprache verwenden, um potenziellen Arbeitgebern zu zeigen, dass Sie sie kennen. Ich würde also alle oben genannten Lösungen in derselben Datei verwenden.
Rodmclaughlin
61

Wenn Sie eine beliebige Liste haben, können Sie diese verwenden Enum.join. Wenn es sich jedoch nur um zwei oder drei handelt, sollte die explizite Verkettung von Zeichenfolgen leichter zu lesen sein

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

Oft müssen Sie es jedoch nicht als einzelne Zeichenfolge im Speicher haben, wenn Sie es beispielsweise über das Netzwerk ausgeben möchten. In diesem Fall kann es vorteilhaft sein, eine Iolist (einen bestimmten Typ einer tiefen Liste) zu verwenden, die Sie vor dem Kopieren von Daten bewahrt. Beispielsweise,

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

Da Sie diese Zeichenfolgen irgendwo als Variablen haben würden, vermeiden Sie durch die Verwendung einer tiefen Liste, eine ganz neue Zeichenfolge zuzuweisen, nur um sie an anderer Stelle auszugeben. Viele Funktionen in elixir / erlang verstehen Iolisten, sodass Sie die zusätzliche Arbeit oft nicht erledigen müssen.

Carlos Martín Nieto
quelle
Wenn Sie am Ende eines Pipe-Befehls "String" |> (& (& 1 <> "\ n")) etwas hinzufügen müssen. ()
hwatkins
9

Der Vollständigkeit halber können Sie auch die String-Interpolation verwenden :

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

Wenn Sie ein Leerzeichen in Ihre Liste einfügen möchten, können Sie es als Iolist behandeln:

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

Dies gibt Ihnen einige Leistungssteigerungen, da Sie keine der Zeichenfolgen im Speicher duplizieren.

Uri
quelle
4

Ein Enum.reduce würde auch für Ihr Beispiel funktionieren, nein?

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

Low Kian Seong
quelle
Ja, aber es braucht eine umgekehrte Enum.reduce (["a", "b", "c"] |> Enum.reverse, fn (x, acc) -> x <> "" <> acc end) "ab c "
Andrei Sura
Ich persönlich denke, dies ist die beste Antwort, da sie sich auf andere Fälle verallgemeinert, in denen Reduce verwendet werden kann. Spricht auf die Idee von "do.call" in R.
Thomas Browne
3

Es hängt davon ab, was Sie versuchen zu tun. Wenn Sie nur versuchen, in eine neue Variable zu schreiben, verwenden Sie einfach Folgendes:

  • String-Interpolation

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
  • String-Konzentration: "StringA" <> " " <> "StringB

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

Wie Uri erwähnte, können IOListen jedoch auch verwendet werden:

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

IOListen werden tatsächlich am leistungsfähigsten sein, wenn Sie sich um den Ressourcenverbrauch kümmern müssen. Die Big Nerd Ranch hat einen guten Überblick über Leistungssteigerungen mit IOListen.

Jason Steinhauser
quelle
2

Es gibt eine Reihe von Methoden, aber wenn Sie wissen, wie mit Nullwerten umgegangen wird, können Sie bestimmen, welche Methode Sie wählen sollten.

Dies wird einen Fehler auslösen

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)

Dadurch wird nur eine leere "" Zeichenfolge eingefügt:

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

Wie wird das:

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

Berücksichtigen Sie auch Typen. Mit <>dir bekommst du kein Free Casting:

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"

Die Leistung in der Praxis scheint ungefähr gleich zu sein:

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}

Kommt also wirklich darauf an, ob du abstürzen willst oder nicht, wenn die interpolierten Werte niloder der falsche Typ sind.

Atomkirk
quelle
0

Sie könnten auch tun 'string A' ++ ' ' ++ 'string B'

Vatsala
quelle
7
Werden sie nicht zur Char-Liste?
Virtuelle
0

Erwägen Sie die Verwendung einer E / A-Liste. Wenn Sie ["String1", "string2"] haben und iolist_to_binary / 1 verwenden, kopieren Sie diese Zeichenfolgen in eine neue Zeichenfolge. Wenn Sie eine E / A-Liste haben, können Sie diese in den meisten Fällen einfach ausgeben und sie wird am Port verkettet. Und das ist der Schlüssel, die Laufzeit muss keine Kopien der Daten erstellen, so dass es viel effizienter als die Verkettung ist.

Zachary K.
quelle