如何根据第三个数组的顺序合并Ruby中两个数组的项?

时间:2022-07-03 12:16:20

I have three arrays.

我有三个阵列。

My main list contains a mix of different entities which are verified in a DB:

我的主列表包含在DB中验证的不同实体的混合:

ab = ["a:555", "b:222", "a:333", "b:777", "a:777", "a:999", "b:111"]

I have two more arrays of a and b entities separated, but ordered (some are missing):

我有另外两个a和b实体的数组分开,但有序(有些丢失):

# notice that some of the items from the initial list are missing, but the order is preserved!
a = [{id}, "a:777", "a:999"]
b = ["b:222", "b:111"]

What is an efficient way to merge a and b in array c preserving the order in ab where the items are present? My expected result from the procedure is:

什么是在数组c中合并a和b的有效方法,保留项目所在的ab中的顺序?我对该程序的预期结果是:

c = ["a:555", "b:222", "a:777", "a:999", "b:111"]

I'm a Ruby newbie and everything I came up with is utterly ugly.

我是一个Ruby新手,我想出的一切都是非常丑陋的。


Edit:

编辑:

I did know it matters, and would be confusing, but a and b are complex objects (AR) that represent the strings in ab. To clarify with my code:

我确实知道这很重要,并且会让人感到困惑,但a和b是表示ab中字符串的复杂对象(AR)。用我的代码澄清:

ab = ["a:555", "b:222", "a:333", "b:777", "a:777", "a:999", "b:111"]
a = [{:id => 555}, {:id => 777}, {:id => 999}]
b = [{:id => 222}, {:id => 111}]
c = []

ab.each { |item|
parts = item.split(":")
if parts[0] == "a"
  if a[0][:id].to_s() == parts[1]
    c << a.shift()
  end
else
  if b[0][:id].to_s() == parts[1]
    c << b.shift()  
  end
end

}

puts c

2 个解决方案

#1


3  

If the value's id are not distinct between a and b, one can do this

如果值的id在a和b之间不明显,则可以执行此操作

c = (
  a.map { |e| [ "a:#{e[:id]}", e ] } +
  b.map { |e| [ "b:#{e[:id]}", e ] }
).
sort_by { |e| ab.index(e.first) }.
map(&:last)

Since you now state they are distinct and that there's a method on the objects that produces your ab key, this is simpler:

既然你现在声明它们是不同的,并且在产生你的ab键的对象上有一个方法,这更简单:

c = (a + b).sort_by { |e| ab.index(e.get_ab_string) }

ab.index is an O(N) operation on ab, so it escalates what's ordinarily a NlnN sort to N^2. To bring the whole solution back into O(NlnN) runtime, one can pre-calaculate the indexes of ab into a hash (an O(N) operation allowing O(1) lookups in the sort_by):

ab.index是对ab的O(N)运算,因此它将通常为NlnN的排序升级为N ^ 2。要将整个解决方案带回O(NlnN)运行时,可以将ab的索引预先计算为哈希(O(N)操作,允许在sort_by中进行O(1)查找):

ab_idx = Hash[ ab.map.with_index { |e,i| [e, i] } ]
c = (a + b).sort_by { |e| ab_idx(e.get_ab_string) }

#2


0  

Here's the basis for how to sort an array into the same order as another. Starting with two arrays:

这是如何将数组排序为与另一个相同的顺序的基础。从两个数组开始:

ary_a = %w[one four three two]
ary_b = [1, 4, 3, 2]

Merge them, sort, then retrieve the one we wanted sorted:

合并它们,排序,然后检索我们想要排序的那个:

ary_a.zip(ary_b).sort_by{ |a, b| b }.map(&:first)
=> ["one", "two", "three", "four"]

If we want to reverse the order:

如果我们想要颠倒顺序:

ary_a.zip(ary_b).sort_by{ |a, b| -b }.map(&:first)
=> ["four", "three", "two", "one"]

or:

要么:

ary_a.zip(ary_b).sort_by{ |a, b| b }.map(&:first).reverse
=> ["four", "three", "two", "one"]

If there are three arrays and two need to be ordered in concert with the third:

如果有三个数组,两个需要与第三个一致排序:

ary_c = %w[a-one a-four a-three a-two]
ary_a.zip(ary_c).zip(ary_b).sort_by{ |a, b| b }.map(&:first)
=> [["one", "a-one"], ["two", "a-two"], ["three", "a-three"], ["four", "a-four"]]

Getting the arrays into the form needed prior to merging and sorting is the problem. Once you have those, and they have equal numbers of elements, it's a pretty simple pattern.

在合并和排序之前将数组放入所需的表单是问题所在。一旦你拥有了它们,并且它们具有相同数量的元素,那么它就是一个非常简单的模式。

#1


3  

If the value's id are not distinct between a and b, one can do this

如果值的id在a和b之间不明显,则可以执行此操作

c = (
  a.map { |e| [ "a:#{e[:id]}", e ] } +
  b.map { |e| [ "b:#{e[:id]}", e ] }
).
sort_by { |e| ab.index(e.first) }.
map(&:last)

Since you now state they are distinct and that there's a method on the objects that produces your ab key, this is simpler:

既然你现在声明它们是不同的,并且在产生你的ab键的对象上有一个方法,这更简单:

c = (a + b).sort_by { |e| ab.index(e.get_ab_string) }

ab.index is an O(N) operation on ab, so it escalates what's ordinarily a NlnN sort to N^2. To bring the whole solution back into O(NlnN) runtime, one can pre-calaculate the indexes of ab into a hash (an O(N) operation allowing O(1) lookups in the sort_by):

ab.index是对ab的O(N)运算,因此它将通常为NlnN的排序升级为N ^ 2。要将整个解决方案带回O(NlnN)运行时,可以将ab的索引预先计算为哈希(O(N)操作,允许在sort_by中进行O(1)查找):

ab_idx = Hash[ ab.map.with_index { |e,i| [e, i] } ]
c = (a + b).sort_by { |e| ab_idx(e.get_ab_string) }

#2


0  

Here's the basis for how to sort an array into the same order as another. Starting with two arrays:

这是如何将数组排序为与另一个相同的顺序的基础。从两个数组开始:

ary_a = %w[one four three two]
ary_b = [1, 4, 3, 2]

Merge them, sort, then retrieve the one we wanted sorted:

合并它们,排序,然后检索我们想要排序的那个:

ary_a.zip(ary_b).sort_by{ |a, b| b }.map(&:first)
=> ["one", "two", "three", "four"]

If we want to reverse the order:

如果我们想要颠倒顺序:

ary_a.zip(ary_b).sort_by{ |a, b| -b }.map(&:first)
=> ["four", "three", "two", "one"]

or:

要么:

ary_a.zip(ary_b).sort_by{ |a, b| b }.map(&:first).reverse
=> ["four", "three", "two", "one"]

If there are three arrays and two need to be ordered in concert with the third:

如果有三个数组,两个需要与第三个一致排序:

ary_c = %w[a-one a-four a-three a-two]
ary_a.zip(ary_c).zip(ary_b).sort_by{ |a, b| b }.map(&:first)
=> [["one", "a-one"], ["two", "a-two"], ["three", "a-three"], ["four", "a-four"]]

Getting the arrays into the form needed prior to merging and sorting is the problem. Once you have those, and they have equal numbers of elements, it's a pretty simple pattern.

在合并和排序之前将数组放入所需的表单是问题所在。一旦你拥有了它们,并且它们具有相同数量的元素,那么它就是一个非常简单的模式。