【问题标题】:How do I merge the items of two arrays in Ruby based on the order of a third array?如何根据第三个数组的顺序在 Ruby 中合并两个数组的项?
【发布时间】:2013-05-09 23:09:27
【问题描述】:

我有三个数组。

我的主列表包含在数据库中验证的不同实体的组合:

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

我还有两个由 ab 实体组成的数组,它们是分开的,但是是有序的(有些是缺失的):

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

在数组c 中合并ab 的有效方法是保留项目所在ab 中的顺序?我的预期结果是:

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

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


编辑:

我确实知道这很重要,而且会让人感到困惑,但 ab 是表示 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

【问题讨论】:

  • 对不起,我没听清楚。你想到了什么?
  • 是的,这个问题令人困惑。
  • 将在一分钟内添加我的代码。
  • @Veseliq 这里的重点是将ab 中的字符串与ab 中的对象进行比较。有用的是知道如何从对象中获取ab 中的字符串,我想您不使用变量名ab 来生成这些字符串。
  • 是否有机会在 ab 中保持相同的值,或者它们始终拥有唯一值?

标签: ruby arrays sorting


【解决方案1】:

如果值的 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)

由于您现在声明它们是不同的,并且对象上有一个方法可以生成您的 ab 键,所以这更简单:

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

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

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

【讨论】:

  • 最后一行,太棒了。如果可以的话,我会加两次。
  • @Priti 你的问题让我很困惑。 sort_by 比您选择 any? 答案更简单、更有效。 sort_by 的运行复杂度为 O( N lnN );你的选择超过任何?是 O( N^2 )
  • @dbenhur 我不想参与任何你知道的辩论。但是我想知道你为什么使用sort_by.as OP 的输出似乎不需要排序。
  • @Priti OP 的问题具体是关于根据ab 中的键顺序生成订单。 sort_by 允许更快的算法——重新访问我的解决方案后,我发现使用 ab.index 忽略了运行时成本;所以我更新了一个条款来消除它。
【解决方案2】:

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

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

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

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

如果我们想颠倒顺序:

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

或:

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

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

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

在合并和排序之前将数组转换为所需的形式是问题所在。一旦你有了这些,并且它们有相同数量的元素,这是一个非常简单的模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2019-11-28
    • 1970-01-01
    相关资源
    最近更新 更多