จะเข้าร่วมสตริงใน Elixir ได้อย่างไร


158

ฉันจะรวมสองสายในรายการด้วยช่องว่างได้อย่างไรเช่น:

["StringA", "StringB"]

กลายเป็น

"StringA StringB"

คำตอบ:


220

หากคุณเพียงแค่ต้องการเข้าร่วมรายการโดยพลการ:

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

หรือเพียงแค่ใช้การแก้ไขสตริง:

 "#{a} #{b}"

ถ้าขนาดของรายการของคุณโดยพลการ:

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

... คำตอบทั้งหมดข้างต้นจะกลับมา

"StringA StringB"

36
ไวยากรณ์ทางเลือกโดยใช้โอเปอเรเตอร์ไพน์ไลน์: ["StringA", "StringB"] |> Enum.join " "
Ryan Cromwell

11
คุณควรหลีกเลี่ยงผู้ดำเนินการไปป์ไลน์เมื่อคุณไม่จำเป็นต้องดำเนินการไพพ์
Carlos

3
@EdMelo สนใจที่จะอธิบายรายละเอียดเกี่ยวกับสาเหตุที่? ในทางเทคนิคแล้วคุณไม่เคย "ต้องการ" อย่างแท้จริงในการปฏิบัติงานไพพ์เนื่องจากพฤติกรรมแบบเดียวกันสามารถทำได้โดยการซ้อนฟังก์ชันการเรียก
Schrockwell

8
@Schrockwell ใช่ "ควร" มากเกินไป สิ่งที่ฉันหมายความว่าคดีนี้คุณมีกำไรในการอ่านเพื่อให้ไม่มีการเรียกฟังก์ชันธรรมดาจะทำให้คิดที่ชัดเจนมากขึ้น
คาร์ลอส

3
คุณควรใช้ภาษา Elixir ให้มากที่สุดเท่าที่จะทำได้เพื่อสาธิตให้นายจ้างที่คุณรู้จัก ดังนั้นฉันจะใช้วิธีแก้ปัญหาทั้งหมดข้างต้นในไฟล์เดียวกัน
rodmclaughlin

61

หากสิ่งที่คุณมีคือรายการที่กำหนดเองคุณสามารถใช้Enum.joinแต่ถ้าเป็นเพียงสองหรือสามรายการการต่อสตริงที่ชัดเจนควรอ่านง่ายขึ้น

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

อย่างไรก็ตามบ่อยครั้งที่คุณไม่จำเป็นต้องใช้มันเป็นสายอักขระเดียวในหน่วยความจำหากคุณกำลังจะเอาท์พุทผ่านเช่นเครือข่าย ในกรณีนี้การใช้ไอโอลิสต์ (รายการเฉพาะแบบลึก) มีประโยชน์สำหรับการทำสำเนาซึ่งช่วยให้คุณประหยัดจากการคัดลอกข้อมูล ตัวอย่างเช่น,

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

เนื่องจากคุณจะต้องมีสตริงเหล่านั้นเป็นตัวแปรอยู่ที่ไหนสักแห่งโดยใช้รายการลึกคุณหลีกเลี่ยงการจัดสรรสตริงใหม่ทั้งหมดเพียงเพื่อส่งออกที่อื่น ฟังก์ชั่นมากมายในยาอายุวัฒนะ / erlang เข้าใจไอโอลิสต์ดังนั้นคุณมักจะไม่จำเป็นต้องทำงานพิเศษ


หากคุณต้องการเพิ่มบางสิ่งในตอนท้ายของคำสั่ง
ไพพ์

9

ตอบรับเพื่อความสมบูรณ์คุณยังสามารถใช้การแก้ไขสตริง :

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

5

หากคุณตกลงกับการเพิ่มช่องว่างในรายการของคุณคุณสามารถถือว่าเป็น iolist:

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

สิ่งนี้จะช่วยเพิ่มการแสดงบางอย่างเนื่องจากคุณไม่ได้ทำซ้ำสตริงใด ๆ ในหน่วยความจำ


4

Enum.reduce จะทำงานด้วยสำหรับตัวอย่างของคุณไม่?

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


ใช่ แต่มันต้องมี Enum.reduce ย้อนกลับ (["a", "b", "c"] |> Enum.reverse, fn (x, acc) -> x <> "" <> จุดสิ้นสุด acc) "ab c "
อังเดรสุระ

โดยส่วนตัวคิดว่านี่เป็นคำตอบที่ดีที่สุดเพราะเป็นการสรุปกรณีอื่น ๆ ที่สามารถใช้การลดได้ พูดถึงแนวคิดของ "do.call" ใน R.
Thomas Browne

3

มันขึ้นอยู่กับสิ่งที่คุณกำลังพยายามที่จะทำ หากคุณเพียงแค่พยายามเขียนตัวแปรใหม่ให้ใช้อย่างใดอย่างหนึ่ง:

  • การแก้ไขสตริง

    a = "StringA"
    b = "StringB"
    "#{a} #{b}"
    
  • การเรียงสตริง: "StringA" <> " " <> "StringB

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

อย่างไรก็ตามดังที่ Uri ได้กล่าวไว้ IOLists ยังสามารถนำมาใช้:

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

IOLists จริง ๆ แล้วจะเป็นคนที่มีประสิทธิภาพมากที่สุดถ้าคุณต้องการดูแลเกี่ยวกับการใช้ทรัพยากร Big Nerd Ranch มีการเขียนเพิ่มประสิทธิภาพที่ดีขึ้นพร้อมกับ IOLists


2

มีหลายวิธี แต่การรู้วิธีจัดการกับค่าศูนย์สามารถกำหนดวิธีการที่คุณควรเลือก

นี่จะทำให้เกิดข้อผิดพลาด

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หรือประเภทผิด



0

พิจารณาใช้รายการ IO หากคุณมี ["String1", "string2"] และคุณใช้ iolist_to_binary / 1 ในนั้นคุณจะคัดลอกสตริงเหล่านั้นลงในสตริงใหม่ หากคุณมีรายการ IO คุณสามารถเอาท์พุทมันในกรณีส่วนใหญ่และมันจะเรียงต่อกันบนพอร์ต และนี่คือกุญแจสำคัญรันไทม์ไม่จำเป็นต้องทำสำเนาข้อมูลดังนั้นมันจึงมีประสิทธิภาพมากกว่าการต่อข้อมูล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.