如何使用Ruby根据另一个数组来排序一个数组

5

有两个数组:

A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
B = [3, 4, 1, 5, 2, 6]

我希望能够按照在数组 A 中的顺序,对 B 中存在于 A 的元素进行排序。

期望的排序结果为:

B #=> [1, 2, 3, 4, 5, 6]

我尝试过去做


B = B.sort_by { |x| A.index }

但是它没有起作用。

这个问题不同于可能的重复问题,因为它涉及到对应数组中元素的存在,并且这里没有哈希表。


1
“B中存在于数组A中的元素” - 那么不在A中的元素呢? - Stefan
1
可能是重复的问题:按另一个数组元素对数组进行排序 - Wand Maker
我已经在@WandMaker处放置了我的评论,指出可能有重复内容。 - Donny
4个回答

24

它完美地工作:

▶ A = [1,3,2,6,4,5,7,8,9,10]
▶ B = [3,4,1,5,2,6]
▶ B.sort_by &A.method(:index)
#⇒ [1, 3, 2, 6, 4, 5]

如果B中可能存在A中不存在的元素,请使用以下代码:

如果 A 中没有 B 中的元素,那么可以将 B 中的元素添加到 A 中:

▶ B.sort_by { |e| A.index(e) || Float::INFINITY }

看起来不需要进行我在答案中做的检查 :) 很好的答案。 - radubogdan
虽然它对于B中不在A中的元素失败了。尝试从A中删除元素3 - radubogdan
完美运行!谢谢 - Donny
只要A中没有B的元素,它就能正常工作。 - radubogdan
@radubogdan 很好的发现,已经更新。我认为你决定删除A元素中不存在的内容是不正确的。 - Aleksei Matiushkin
我决定删除A中不存在的元素是为了表明一点并创造更好的答案 :) 无论如何,我从一开始就赞同你。 - radubogdan

2

我建议首先检查B中存在哪些元素也在A中:

B & A

然后对其进行排序:

(B & A).sort_by { |e| A.index(e) }

2
首先考虑每个元素都在A中的情况,就像问题的例子一样,B中的每个元素都在A中:B
A = [1,2,3,4,5,6,7,8,9,10]
B = [3,6,1,5,1,2,1,6]

可以这样写,只需要对A进行一次遍历(构建g1),并对B进行一次遍历。

g = A.each_with_object({}) { |n,h| h[n] = 1 }
  #=> {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1, 10=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
  #=> [1, 1, 1, 2, 3, 5, 6, 6]

如果不能保证B的所有元素都在A中,并且不在其中的任何元素都将放置在排序数组的末尾,则可以稍微更改g的计算方式。
g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }

这需要再经过A和B各一次。
例如,假设:
A = [2,3,4,6,7,8,9]

并且B保持不变。然后,

g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }
  #=> {2=>1, 3=>1, 4=>1, 6=>1, 7=>1, 8=>1, 9=>1, 1=>1, 5=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
  #=> [2, 3, 6, 6, 1, 1, 1, 5]

这个解决方案展示了Ruby v1.9中有争议的哈希属性更改的价值:哈希表从此保证维护键插入的顺序。
1 我认为可以写成g = A.product([1]).to_h,但是文档Array#to_h不能保证返回的哈希表中键的顺序与A中的顺序相同。

如果B的每个元素都在A中,那么这个解决方案绝对是最优雅的。 - Aleksei Matiushkin
1
@mudasobwa,我做了一些改变,你可能会感兴趣。 - Cary Swoveland

1

你在 A.index 中错过了 x,所以查询应该是:

B = B.sort_by { |x| A.index(x) }

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