ผสานและแทรกสองอาร์เรย์ใน Ruby


106

ฉันมีรหัสต่อไปนี้:

a = ["Cat", "Dog", "Mouse"]
s = ["and", "&"]

ฉันต้องการรวมอาร์เรย์sเป็นอาร์เรย์aซึ่งจะทำให้ฉัน:

["Cat", "and", "Dog", "&", "Mouse"]

เมื่อมองผ่าน Ruby Array และเอกสาร Enumerable ฉันไม่เห็นวิธีการดังกล่าวที่จะทำให้สำเร็จได้

มีวิธีที่ฉันสามารถทำได้โดยไม่ต้องทำซ้ำในแต่ละอาร์เรย์หรือไม่?


a จะมี 3 องค์ประกอบเสมอและ s สอง? ตัวอย่างเพิ่มเติมจะเป็นประโยชน์
tokland

คำตอบ:


171

คุณสามารถทำได้ด้วย:

a.zip(s).flatten.compact

4
เกิดอะไรขึ้นถ้าaมีมากกว่า 3 องค์ประกอบ?
Michael Kohl

116
["a", "b"] .concat (["c", "d"]) # => ["a", "b", "c", "d"]
Leo Romanovsky

31
@Leo, @chuck: ถ้าคุณอ่านตัวอย่างที่คุณจะเห็นว่าคริสอยากจะแทรกองค์ประกอบที่ไม่เชื่อมพวกเขา โดยพื้นฐานแล้วเขาต้องการ[a, s].transposeยกเว้นว่าสองแถวไม่เป็นไปตามนั้นปล่อยให้#zipเป็นทางออกที่ชัดเจน และฉันไม่เชื่อว่าเขาหมายความว่าเขาสนใจจริงๆว่าจะaกลายพันธุ์หรือไม่... ฉันไม่คิดว่าเขากำลังแสดงความคิดเห็นเกี่ยวกับโซลูชันที่กลายพันธุ์และใช้งานได้เลยเขาแค่พยายามอธิบายรูปแบบ
DigitalRoss

15
+1 สำหรับการเป็นคนเดียวที่อ่านคำถามของ blummin จริงๆ! > _ <
Matt Fletcher

5
ที่สำคัญกว่านั้นจะเกิดอะไรขึ้นถ้าอาร์เรย์ทั้งสองมีความยาวไม่เท่ากัน? โดยเฉพาะอย่างยิ่งถ้า s เป็นอีกต่อไป? ฉันคิดว่าฉันสามารถสันนิษฐานได้อย่างปลอดภัยว่าตัวอย่างที่คริสให้นั้นไม่ใช่ข้อมูลจริงที่เขาทำงานด้วย พิจารณา: [] .zip [1, 2] => nil (จะมีปัญหาในการเรียก #flatten ในสิ่งนั้น) [3,4] .zip ([1, 3, 5, 7]) => [[3 , 1], [4, 3]] (อ๊ะเดาว่าเราไม่สนใจองค์ประกอบสุดท้ายในอาร์เรย์ที่ 2)
hoff2

33

สิ่งนี้จะไม่ให้อาร์เรย์ผลลัพธ์ตามลำดับที่คริสถาม แต่ถ้าลำดับของอาร์เรย์ผลลัพธ์ไม่สำคัญคุณก็สามารถa |= bใช้ได้ หากคุณไม่ต้องการกลายพันธุ์aคุณสามารถเขียนa | bและกำหนดผลลัพธ์ให้กับตัวแปรได้

ดูเอกสารชุดยูเนี่ยนสำหรับการเรียนอาร์เรย์ที่http://www.ruby-doc.org/core/classes/Array.html#M000275

คำตอบนี้ถือว่าคุณไม่ต้องการให้องค์ประกอบอาร์เรย์ซ้ำกัน หากคุณต้องการอนุญาตให้ทำซ้ำองค์ประกอบในอาร์เรย์สุดท้ายของคุณa += bควรทำเคล็ดลับ อีกครั้งหากคุณไม่ต้องการกลายพันธุ์aให้ใช้a + bและกำหนดผลลัพธ์ให้กับตัวแปร

เพื่อตอบสนองต่อความคิดเห็นบางส่วนในหน้านี้โซลูชันทั้งสองนี้จะทำงานร่วมกับอาร์เรย์ทุกขนาด


อันนี้น่าจะดีที่สุดแน่นอน
ardavis

12
สิ่งนี้ให้["Cat", "Dog", "Mouse", "and", "&"]ซึ่งไม่ใช่สิ่งที่ OP ต้องการ
Andrew Grimm

ยอดเยี่ยมแอนดรูว์ ฉันจะอัปเดตคำตอบเพื่อบอกว่าฉันไม่ได้ตอบคำถามของคริส
Michael Stalker

29

หากคุณไม่ต้องการให้ซ้ำกันทำไมไม่ใช้ตัวดำเนินการยูเนี่ยน :

new_array = a | s

1
ให้รางวัล +1 สำหรับโซลูชันที่เรียบง่ายและหรูหรา
Giacomo1968

ตอบโจทย์แน่นอน! คำถามคือ: "ฉันต้องการรวมอาร์เรย์เข้ากับอาร์เรย์ a"
ดักลาส

ทางออกที่ดี - แต่จะเปลี่ยนลำดับของผลลัพธ์ ผลลัพธ์จากsจะอยู่ที่ส่วนท้ายของอาร์เรย์ใหม่
Hendrik

2
ลำดับขององค์ประกอบจะไม่เป็นไปตามที่ OP ต้องการ
tokland

6
s.inject(a, :<<)

s   #=> ["and", "&"]
a   #=> ["Cat", "Dog", "Mouse", "and", "&"]

ไม่ได้ให้คำสั่งซื้อที่คุณขอ แต่เป็นวิธีที่ดีในการรวมอาร์เรย์สองอาร์เรย์เข้าด้วยกัน


ฉันชอบมันสั้นและสะอาด :)
Nafaa Boutefer

6

นี่คือโซลูชันที่ช่วยให้สามารถแทรกอาร์เรย์หลายขนาดที่มีขนาดแตกต่างกันได้ (โซลูชันทั่วไป):

arr = [["Cat", "Dog", "Mouse", "boo", "zoo"],
 ["and", "&"],
 ["hello", "there", "you"]]

first, *rest = *arr; first.zip(*rest).flatten.compact
=> ["Cat", "and", "hello", "Dog", "&", "there", "Mouse", "you", "boo", "zoo"]

2
ดี! ข้อ จำกัด ประการหนึ่งอาร์เรย์แรกต้องยาวที่สุด
Brian Low

@BrianLow จับมาก!
Abdo

5

มันไม่ได้สวยหรู แต่ใช้ได้กับอาร์เรย์ทุกขนาด:

>> a.map.with_index { |x, i| [x, i == a.size - 2 ? s.last : s.first] }.flatten[0..-2] 
#=> ["Cat", "and", "Dog", "&", "Mouse"]

+1 สำหรับการจัดการกับกรณีขอบแปลก ๆ ฉันคิดว่าi = s.cycle; a.map { |x| [x, i.next] }.flatten[0..-2]จะใช้ได้พอ ๆ กัน
สั้นเกินไป

ฉันไม่แน่ใจว่า OP ต้องการสลับกันandหรือ&ไม่ดังนั้นฉันจึงพาเขาไปให้ได้มากที่สุดโดยปล่อยให้aมีความยาวเท่าใดก็ได้
Michael Kohl

3

วิธีแก้ปัญหาทั่วไปที่ใช้งานได้แม้ว่าอาร์เรย์แรกจะไม่ยาวที่สุดและยอมรับอาร์เรย์จำนวนเท่าใดก็ได้

a = [
    ["and", "&"],
    ["Cat", "Dog", "Mouse"]
]

b = a.max_by(&:length)
a -= [b]
b.zip(*a).flatten.compact

 => ["Cat", "and", "Dog", "&", "Mouse"]

2

วิธีจัดการกับสถานการณ์ที่ทั้งสองa& sมีขนาดไม่เท่ากัน:

a.zip(s).flatten.compact | s
  • .compactจะลบออกnilเมื่อaมีขนาดใหญ่กว่าs
  • | sจะเพิ่มรายการที่เหลือsเมื่อaมีขนาดเล็กกว่าs

1

วิธีหนึ่งในการทำ interleave และยังรับประกันว่าอาร์เรย์ใดเป็นอาร์เรย์ที่ใหญ่ที่สุดสำหรับวิธี zip คือการเติมอาร์เรย์หนึ่งในอาร์เรย์nilจนถึงขนาดอาร์เรย์อื่น ด้วยวิธีนี้คุณยังรับประกันได้ว่าองค์ประกอบของอาร์เรย์ใดจะอยู่ในตำแหน่งแรก:

preferred_arr = ["Cat", "Dog", "Mouse"]
other_arr = ["and","&","are","great","friends"]

preferred_arr << nil while preferred_arr.length < other_arr.length
preferred_arr.zip(other_arr).flatten.compact
#=> ["Cat", "and", "Dog", "&", "Mouse", "are", "great", "friends"]

1
ดีกว่าเล็กน้อย: preferred_arr.zip(other_arr).flatten | other_arr(โดยไม่ต้องเติมศูนย์)
Adam Fendley

-2
arr = [0, 1]
arr + [2, 3, 4]

//outputs [0, 1, 2, 3, 4]

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