İksir dizeleri nasıl birleştirilir?


158

Boşluk içeren bir listede iki dizeyi nasıl birleştiririm:

["StringA", "StringB"]

olur

"StringA StringB"

Yanıtlar:


220

Sadece rastgele bir listeye katılmak istiyorsanız:

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

veya yalnızca dize enterpolasyonunu kullanın:

 "#{a} #{b}"

Liste boyutunuz keyfi ise:

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

... yukarıdaki tüm çözümler geri dönecek

"StringA StringB"

36
Boru hattı operatörünü kullanan alternatif sözdizimi: ["StringA", "StringB"] |> Enum.join " "
Ryan Cromwell

11
Boru işlemlerine gerçekten ihtiyacınız olmadığında boru hattı operatöründen kaçınmalısınız.
Carlos

3
@EdMelo Nedenini açıklamak ister misiniz? Teknik olarak hiçbir zaman borulama işlemlerine gerçek anlamda “ihtiyaç duymazsınız”, çünkü aynı davranış fonksiyon çağrılarını iç içe yerleştirerek elde edilebilir.
Schrockwell

8
@Schrockwell evet, "gerekir" çok fazlaydı. Demek istediğim, bu durumda okunabilirlikte herhangi bir kazancınız yok, bu yüzden basit bir işlev çağrısı, düşüncelerin daha açık olmasını sağlayacaktır.
Carlos

3
Potansiyel işverenlere tanıdığınızı göstermek için İksir dilinin mümkün olduğunca fazlasını kullanmalısınız. Bu yüzden yukarıdaki tüm çözümleri aynı dosyada kullanırdım.
rodmclaughlin

61

Sahip olduğunuz rastgele bir listeyse, kullanabilirsiniz Enum.join, ancak yalnızca iki veya üç içinse, açık dize birleştirmenin okunması daha kolay olmalıdır

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

Bununla birlikte, örneğin ağ üzerinden çıkış yapacaksanız, genellikle bellekte tek bir dize olması gerekmez. Bu durumda, verileri kopyalamaktan koruyan bir iolist (belirli bir derin liste türü) kullanmak avantajlı olabilir. Örneğin,

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

Bu dizeleri bir yerde değişken olarak alacağınız için, derin bir liste kullanarak, başka bir yerde çıktı almak için tamamen yeni bir dize ayırmaktan kaçınırsınız. İksir / erlang'daki birçok fonksiyon iolistleri anlar, bu yüzden ekstra iş yapmanıza gerek kalmaz.


Bir boru komutunun sonuna bir şey eklemeniz gerekiyorsa "String" |> (& (& 1 <> "\ n")). ()
hwatkins

9

Tamlık için cevap verirseniz, String enterpolasyonunu da kullanabilirsiniz :

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

5

Listenize bir boşluk eklemeyle ilgili sorun yaşadıysanız, bunu bir liste listesi olarak değerlendirebilirsiniz:

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

Bu, bellekteki dizeleri çoğaltmamanız nedeniyle bazı performans artışları sağlar.


4

Bir Enum.reduce örnek numaranız için de işe yarar mı?

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


Evet, ancak ters bir Enum.reduce (["a", "b", "c"] |> Enum.reverse, fn (x, acc) -> x <> "" <> acc end) "ab c "
Andrei Sura

kişisel olarak bunun en iyi cevap olduğunu düşünün çünkü azaltmanın kullanılabileceği diğer durumları genelleştirir. R'de "do.call" fikrinden bahsediyor
Thomas Browne

3

Ne yapmaya çalıştığınıza bağlıdır. Sadece yeni bir değişkene yazmaya çalışıyorsanız, aşağıdakilerden birini kullanın:

  • Dize enterpolasyonu

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
  • Dize birleştirme: "StringA" <> " " <> "StringB

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

Bununla birlikte, Uri'nin belirttiği gibi, IOListler de kullanılabilir:

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

Kaynak tüketimini önemsemeniz gerekiyorsa aslında IOListler en yüksek performans göstereceklerdir. Big Nerd Ranch, IOLists ile performans kazançları hakkında iyi bir yazıya sahiptir.


2

Birkaç yöntem vardır, ancak nil değerlerini nasıl işlediğini bilmek hangi yöntemi seçmeniz gerektiğini belirleyebilir.

Bu bir hata verecektir

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)

Bu sadece boş bir "" dizesi ekleyecektir:

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

Bu şekilde:

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

Ayrıca türleri de göz önünde bulundurun. İle <>size herhangi bir serbest casting alamadım:

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"

Uygulamadaki performans aşağı yukarı aynı görünüyor:

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}

Bu nedenle, enterpolasyonlu değerler nilveya yanlış tip olduğunda çökmek isteyip istemediğinize gerçekten bağlıdır .


0

Ayrıca yapabilirsin 'string A' ++ ' ' ++ 'string B'


7
Char listesi olmayacaklar mı?
Sanal

0

Bir IO Listesi kullanmayı düşünün, eğer ["String1", "string2"] varsa ve üzerinde iolist_to_binary / 1 kullanıyorsanız, bu dizeleri yeni bir dizeye kopyalayacaksınız. Bir ES listeniz varsa, çoğu durumda listenin çıktısını alabilirsiniz ve bu bağlantı noktasını bağlantı noktasında birleştirir. Ve bu anahtar şeydir, çalışma zamanının verilerin kopyalarını alması gerekmez, böylece birleştirme işleminden çok daha verimlidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.