如何在Elixir中连接字符串?

如何在Elixir中连接字符串?,elixir,Elixir,如何用空格将列表中的两个字符串连接起来,如: ["StringA", "StringB"] 变成 "StringA StringB" 如果您只想加入任意列表: "StringA" <> " " <> "StringB" 如果您的列表大小是任意的: Enum.join(["StringA", "StringB"], " ") 。。。以上所有解决方案都将返回 "StringA StringB" 如果您拥有的是一个任意列表,那么您可以使用Enum.join,但如果它仅

如何用空格将列表中的两个字符串连接起来,如:

["StringA", "StringB"]
变成

"StringA StringB"

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

"StringA" <> " " <> "StringB"
如果您的列表大小是任意的:

Enum.join(["StringA", "StringB"], " ")
。。。以上所有解决方案都将返回

"StringA StringB"

如果您拥有的是一个任意列表,那么您可以使用
Enum.join
,但如果它仅用于两个或三个列表,则显式字符串串联应该更易于阅读

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

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

对于您的示例,Enum.reduce也可以

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

“StringB StringA”

您也可以执行
'string A'++'++'++'string B'

如果您同意在列表中添加空格,您可以将其视为一个列表:

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

这会提高性能,因为您不会复制内存中的任何字符串。

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

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

这取决于你想做什么。如果您只是尝试写入一个新变量,则只需使用以下任一选项:

  • 字符串插值

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

  • Enum.join()

然而,如Uri所述,也可以使用IOList:

[“StringA”,“StringB”]|>IO.iodata_到_二进制文件


如果你需要关心资源消耗的话,IOLists实际上将是最具性能的。Big Nerd Ranch与IOLists一起提高性能。

如果你有[“String1”,“string2”],考虑使用IO列表你在上面使用iolist\u to\u binary/1,然后你会把这些字符串复制成一个新的字符串。如果你有一个IO列表,你可以在大多数情况下输出它,它会在端口上连接它。这是关键,运行时不需要复制数据,所以它比连接更有效。

有很多m方法,但知道它如何处理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(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(5)>“我的名字是”1
**(ArgumentError)运算符中应为二进制参数,但得到:1
(elixir)lib/kernel.ex:1767:kernel.wrap\u串联/3
(elixir)lib/kernel.ex:1758:kernel.extract\u串联/2
(elixir)lib/kernel.ex:1754:kernel.extract\u串联/2
(elixir)扩展宏:内核。/2
iex:5:(文件)
iex(5)>“我的名字是#{1}”
“我的名字是1”
iex(7)>Enum.join([“我的名字是”,1],“”)
“我的名字是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}
iex(22)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是”“adam”end)end)
{8023855,:ok}
iex(23)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是”“亚当”结束)结束)
{8528052,:ok}
iex(24)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是”“亚当”结束)结束)
{7778532,:ok}
iex(25)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是#{“亚当”}”end)end)
{7620582,:ok}
iex(26)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是#{“亚当”}”end)end)
{7782710,:ok}
iex(27)>:timer.tc(fn->Enum.each(1..10_000_000,fn->“我的名字是#{“亚当”}”end)end)
{7743727,:ok}

因此,这实际上取决于当插值为
nil
或类型错误时是否要崩溃。

使用管道操作符的替代语法:
[“StringA”,“StringB”]|>Enum.join”“
当您实际上不需要管道操作时,应避免使用管道操作符。@EdMelo想详细说明原因吗?从技术上讲,您永远不会真正“需要”管道操作,因为嵌套函数调用可以实现相同的行为。@Schrockwell是的,“应该”太多了。我的意思是,在这种情况下,您在可读性方面没有任何好处,因此简单的函数调用将使思考更加明确。您应该尽可能多地使用长生不老药语言,以便向潜在雇主证明您了解它。所以我会在同一个文件中使用上面所有的解决方案。它们不会变成字符列表吗?是的,但它需要一个反向枚举。reduce([“a”,“b”,“c”]|>Enum.reverse,fn(x,acc)->x“acc end)”a b c我个人认为这是最好的答案,因为它推广到了可以使用reduce的其他情况。谈到了R中“do.call”的概念。如果需要在管道命令“String”|>(&(&1“\n”))的末尾添加一些内容,这非常有用,但在常见情况下,如果其中一个字符串为nil,则希望消除空格,但
Enum.join([“StringA”,nil],“”)=“StringA”
而不是
“StringA”
这正是我想要的——一种非常干净的处理这种情况的方法。
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}