如何在Elixir中加入字符串?

thi*_*ofm 136 elixir

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

["StringA", "StringB"]
Run Code Online (Sandbox Code Playgroud)

"StringA StringB"
Run Code Online (Sandbox Code Playgroud)

thi*_*ofm 197

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

"StringA" <> " " <> "StringB"
Run Code Online (Sandbox Code Playgroud)

或者只是使用字符串插值:

 "#{a} #{b}"
Run Code Online (Sandbox Code Playgroud)

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

Enum.join(["StringA", "StringB"], " ")
Run Code Online (Sandbox Code Playgroud)

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

"StringA StringB"
Run Code Online (Sandbox Code Playgroud)

  • 使用管道运算符的替代语法:`["StringA","StringB"] |> Enum.join""` (33认同)
  • 当您实际上不需要管道操作时,应该避免使用管道操作符. (8认同)
  • @Schrockwell是的,"应该"太多了.我的意思是,这种情况下你没有获得可读性,所以一个简单的函数调用会使思考更明确. (5认同)
  • 您应该尽可能多地使用 Elixir 语言,以便向潜在雇主证明您了解它。所以我会在同一个文件中使用上面的所有解决方案。 (5认同)
  • @EdMelo关心详细说明原因?从技术上讲,您从未真正"需要"管道操作,因为嵌套函数调用可以实现相同的行为. (3认同)

Car*_*eto 59

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

"StringA" <> " " <> "StringB"
Run Code Online (Sandbox Code Playgroud)

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

iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok
Run Code Online (Sandbox Code Playgroud)

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


She*_*yar 9

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

iex(1)> [a, b] = ["StringA", "StringB"]
iex(2)> "#{a} #{b}"
"StringA StringB"
Run Code Online (Sandbox Code Playgroud)


小智 7

这取决于你想要做什么。如果您只是想写出一个新变量,那么只需使用:

  • 字符串插值

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
    Run Code Online (Sandbox Code Playgroud)
  • 字符串连接: "StringA" <> " " <> "StringB

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

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

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

如果您需要关心资源消耗,IOLists 实际上将是性能最高的。Big Nerd Ranch 有一篇关于使用 IOLists 提高性能的文章。


Low*_*ong 5

一个Enum.reduce也可以用于你的例子吗?

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


Uri*_*Uri 5

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

["StringA", " ", "StringB"] |> IO.iodata_to_binary # "StringA StringB"
Run Code Online (Sandbox Code Playgroud)

这为您提供了一些性能提升,因为您不会复制内存中的任何字符串。


ato*_*irk 5

有很多方法,但是知道它如何处理 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)
Run Code Online (Sandbox Code Playgroud)

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

iex(1)> "my name is #{nil}"
"my name is "
Run Code Online (Sandbox Code Playgroud)

就像这样:

iex(3)> Enum.join(["my name is", nil], " ")
"my name is "
Run Code Online (Sandbox Code Playgroud)

还要考虑类型。随着<>你没有得到任何自由铸造:

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"
Run Code Online (Sandbox Code Playgroud)

实践中的性能似乎大致相同:

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}
Run Code Online (Sandbox Code Playgroud)

因此,实际上取决于您是否想在插值nil或错误类型时崩溃。