在Ruby中合并和交错两个数组

107

我有以下代码:

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

我想将数组s合并到数组a中,这将给我:

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

查看 Ruby 数组和 Enumerable 文档,我没有找到可以完成这个任务的方法。

有没有一种方法可以不通过遍历每个数组来实现这个目标?


a数组将始终具有3个元素,而s数组则有两个?提供一些更多的示例会更有帮助。 - tokland
13个回答

172
你可以使用以下代码实现:
a.zip(s).flatten.compact

4
如果 a 具有超过 3 个元素,会怎样? - Michael Kohl
118
["a", "b"].concat(["c", "d"]) 会得到 [ "a", "b", "c", "d" ] 的结果。该代码将两个数组合并成一个新的数组。第一个数组是 ["a", "b"],第二个数组是 ["c", "d"],它们被连接在一起形成了新的数组 [ "a", "b", "c", "d" ]。 - Leo Romanovsky
31
@Leo,@chuck:如果你们看了例子,就会发现Chris想要交错元素,而不是连接它们。基本上,他想要[a, s].transpose,但两行不符合要求,所以#zip是显而易见的解决方案。我认为他并不在意a是否被改变……我不认为他在评论可变vs函数式解决方案,他只是试图描述这种模式。 - DigitalRoss
17
+1 是因为你是唯一一个真正读懂了该死的问题的人!>_<(注:原文中的“blummin'”是一种口语化的表达,表示厌烦或不满之情。) - Matt Fletcher
5
更重要的是,如果这两个数组长度不相等怎么办?特别是当 s 数组更长时?我认为可以安全地假设 Chris 给出的示例并不是他实际处理的数据。考虑以下情况:[].zip[1, 2] => nil(很难对其调用 #flatten 方法) [3,4].zip([1, 3, 5, 7]) => [[3, 1], [4, 3]](糟糕了,看来我们不关心第二个数组中的最后几个元素) - hoff2
显示剩余6条评论

34

这种方法不能按照Chris的要求给出一个结果数组,但是如果结果数组的顺序不重要,你可以使用a |= b。如果你不想改变a,你可以写成a | b并将结果赋值给一个变量。

请参阅Array类的集合并文档

此答案假设您不希望在最终数组中包含重复元素。如果您允许在最终数组中包含重复元素,则a += b应该可以解决问题。同样,如果您不想改变a,请使用a + b并将结果赋值给一个变量。

针对本页面的一些评论,这两个解决方案适用于任何大小的数组。


这个看起来绝对是最好的。 - ardavis
12
这会得到["猫", "狗", "老鼠", "和", "&"],这不是原作者想要的。 - Andrew Grimm
很好的提醒,安德鲁。我会更新我的回答并说明我没有回答克里斯的问题。 - Michael Stalker

31

如果你不想要重复的元素,为什么不使用 并集运算符 呢:

new_array = a | s

2
对于一个被低估的、简单而优雅的解决方案,奖励+1。 - Giacomo1968
当然回答了这个问题!问题是:“我想将数组 s 合并到数组 a 中”。 - Douglas
好的解决方案 - 但这会改变结果的顺序。来自s的结果将位于新数组的末尾。 - Hendrik
2
元素的顺序可能不是原帖作者想要的。 - tokland

6
s.inject(a, :<<)

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

它不会按照你所请求的顺序给出结果,但它是一种很好的合并两个数组的方式,通过将一个数组追加到另一个数组后面。


我喜欢它,简短而干净。 :) - Nafaa Boutefer
1
不像 a | s 那样简短和干净。 - Harry Wood

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"]

3
好的!有一个限制,第一个数组必须是最长的。 - 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] 也同样有效。 - mu is too short
我不确定 OP 是否想要交替使用 and&,因此我尽可能地按照字面意思理解,同时允许任意长度的 a - Michael Kohl

5
为处理 as 大小不同的情况:
a.zip(s).flatten.compact | s
  • .compact将在a大于s时删除nil
  • | s将在a小于s时添加s中剩余的项目

3
如何提供一种更通用的解决方案,即使第一个数组不是最长的,也可以接受任意数量的数组?
a = [
    ["and", "&"],
    ["Cat", "Dog", "Mouse"]
]

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

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

1

一种实现交错操作并保证其中一个数组是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(不需要填充 nil 值) - Adam Fendley

0
一个非常清晰的合并多个数组的方法是将它们解包成一个数组。这在许多语言中实际上都是以几乎相同的方式工作的,因此我更喜欢使用这种方法,因为它简单易懂,开发人员也很熟悉它。
a = ["Cat", "Dog", "Mouse"]
s = ["and", "&"]

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接