如何在Elixir中加入字符串?

时间:2013-12-29 19:43:18

标签: elixir

如何在带有空格的列表中连接两个字符串,例如:

["StringA", "StringB"]

变为

"StringA StringB"

9 个答案:

答案 0 :(得分:178)

如果您只想加入一些任意列表:

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

或只使用字符串插值:

 "#{a} #{b}"

如果您的列表大小是任意的:

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

......以上所有解决方案都将返回

"StringA StringB"

答案 1 :(得分:57)

如果你拥有的是一个任意列表,那么你可以使用Enum.join,但如果只有两个或三个,显式字符串连接应该更容易阅读

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

然而,如果您要通过例如输出它,通常不需要将它作为单个字符串存储在内存中。网络。在这种情况下,使用iolist(特定类型的深度列表)可能是有利的,这可以避免复制数据。例如,

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

由于您将这些字符串作为变量放在某处,通过使用深层列表,您可以避免分配一个全新的字符串,只是为了将其输出到别处。 elixir / erlang中的许多函数都理解iolists,因此您通常不需要做额外的工作。

答案 2 :(得分:9)

为了完整性,您还可以使用字符串插值

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

答案 3 :(得分:5)

Enum.reduce对你的例子也有用吗?

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

答案 4 :(得分:4)

有很多方法,但是了解它如何处理nil值可以确定您应该选择哪种方法。

这将引发错误

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)

这只会插入一个空白的“”字符串:

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

这将会:

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

还要考虑类型。使用<>,您将无法获得任何免费转换:

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"

实践中的表现大致相同:

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}

因此,实际上取决于插入值是nil还是类型错误时是否要崩溃。

答案 5 :(得分:3)

如果您可以在列表中添加空格,则可以将其视为iolist:

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

这会给你一些性能提升,因为你没有复制内存中的任何字符串。

答案 6 :(得分:3)

这取决于您要执行的操作。如果您只是想写出一个新变量,请使用以下任一方法:

  • 字符串插值

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
  • 字符串连接:"StringA" <> " " <> "StringB

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

但是,正如Uri所提到的,也可以使用IOLists:

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

如果您需要关心资源消耗,那么

IOList实际上将是性能最高的。 Big Nerd Ranch拥有a good write-up的IOLists性能提升。

答案 7 :(得分:0)

你也可以'string A' ++ ' ' ++ 'string B'

答案 8 :(得分:0)

考虑使用IO列表,如果您具有[“ String1”,“ string2”]并在其上使用iolist_to_binary / 1,则将这些字符串复制到新字符串中。如果您有IO列表,则在大多数情况下可以将其输出,并将其连接在端口上。这是关键,运行时不需要复制数据,因此它比串联更有效。