【问题标题】:Ruby, remove super-arraysRuby,删除超级数组
【发布时间】:2019-09-19 19:10:15
【问题描述】:

如果我有一个数组数组A,并且想删除A 中的所有数组,而A 中也有一个子数组,我该怎么做。在这种情况下,array_1array_2 的子数组,如果array_1 - array_2 = []。在多个数组只是相同元素的重新排列版本的情况下,如果您可以摆脱除其中一个之外的所有数组,则可以加分,但如果更容易,您可以随意处理。

在 python 中,我可以很容易地使用理解,A 是一组冻结集:

A = {a for a in A if all(b-a for b in A-{a})}

有没有一种简单的方法可以用 ruby​​ 编写这个?我不在乎A 的顺序或它的数组是否被保留。此外,在我的程序中,没有一个数组有重复的元素,如果这会让事情变得更容易/更快的话。

示例

A = [[1,6],[1,2],[2,4],[3,5],[1,3,6],[2,3,6]] 
# [1,6] is a subarray of [1,3,6], so [1,3,6] should be removed
remove_super_arrays(A) 
> A = [[1,6],[1,2],[2,4],[3,5],[2,3,6]] 

A = [[1,2,4],[2,3,4],[1,4,5],[2,6]]
# although there is overlap, there are no subarrays, so nothing should be removed
remove_super_arrays(A)
> A = [[1,2,4],[2,3,4],[1,4,5],[2,6]]

A = [[1],[2,1,3],[2,4],[1,4]]
# [1] is a subarray of [2,1,3] and [1,4]
remove_super_arrays(A)
> A = [[1],[2,4]]

【问题讨论】:

  • 如果A = [[1,2], [2,1]],期望的返回值是多少? A的其余元素是否必须与A中的顺序相同?
  • 订购无关紧要,A = [[1,2], [2,1]] 对我的目的来说并不重要,它可能会引发错误,我不介意,但我已经添加了我希望它如何工作回答。
  • 我不懂 Python,但我怀疑你的 Python 表达式有一个小问题。请参阅我在答案末尾添加的替代计算部分中使用select的方法。

标签: ruby


【解决方案1】:

代码

def remove_super_arrays(arr)
  order = arr.each_with_index.to_a.to_h
  arr.sort_by(&:size).reject.with_index do |a,i|
    arr[0,i].any? { |aa| (aa.size < a.size) && (aa-a).empty? }
  end.sort_by { |a| order[a] }
end

示例

remove_super_arrays([[1,6],[1,2],[2,4],[3,5],[1,3,6],[2,3,6]] ) 
  #=> [[1,6],[1,2],[2,4],[3,5],[2,3,6]]

remove_super_arrays([[1,2,4],[2,3,4],[1,4,5],[2,6]])
  #=> [[1,2,4],[2,3,4],[1,4,5],[2,6]]

remove_super_arrays([[1],[2,1,3],[2,4],[1,4]])
  #=> [[1],[2,4]]

说明

考虑第一个例子。

arr = [[1,6],[1,2],[2,4],[3,5],[1,3,6],[2,3,6]]

我们先保存a的元素位置

order = arr.each_with_index.to_a.to_h # save original order
  #=> {[1, 6]=>0, [1, 2]=>1, [2, 4]=>2, [3, 5]=>3, [1, 3, 6]=>4, [2, 3, 6]=>5}

然后拒绝arr的元素:

b = arr.sort_by(&:size)
  #=> [[1, 6], [1, 2], [2, 4], [3, 5], [1, 3, 6], [2, 3, 6]]
c = b.reject.with_index do |a,i|
  arr[0,i].any? { |aa| (aa.size < a.size) && (aa-a).empty? }
end
  #=> [[1, 6], [1, 2], [2, 4], [3, 5], [2, 3, 6]] 

最后,对c 重新排序以对应arr 元素的原始排序。

c.sort_by { |a| order[a] }
  #=> [[1, 6], [1, 2], [2, 4], [3, 5], [2, 3, 6]]

在这种情况下恰好与 c 的元素顺序相同。

我们再仔细看看c的计算:

enum1 = b.reject
  #=> #<Enumerator: [[1, 6], [1, 2], [2, 4], [3, 5], [1, 3, 6],
  #     [2, 3, 6]]:reject> 
enum2 = enum1.with_index
  #=> #<Enumerator: #<Enumerator: [[1, 6], [1, 2], [2, 4], [3, 5],
  #     [1, 3, 6], [2, 3, 6]]:reject>:with_index> 

第一个元素由枚举器enum2 生成并传递给块并分配为块变量的值:

a, i = enum2.next
  #=> [[1, 6], 0] 
a #=> [1, 6] 
i #=> 0 

然后进行块计算:

d = arr[0,i]
  #=> [] 
d.any? { |aa| (aa.size < a.size) && (aa-a).empty? }
  #=> false 

所以a[0] 不会被拒绝。 enum2 传递给块的下一对是[[1, 2], 1]。该值也被保留,但让我们跳到 enum2 传递给块的最后一个元素:

a, i = enum2.next
  #=> [[1, 2], 1] 
a, i = enum2.next
  #=> [[2, 4], 2] 
a, i = enum2.next
  #=> [[3, 5], 3]

a, i = enum2.next
  #=> [[1, 3, 6], 4] 
a #=> [1, 3, 6]
i #=> 4 

执行块计算:

d = arr[0,i]
  #=> [[1, 6], [1, 2], [2, 4], [3, 5]] 
d.any? { |aa| (aa.size < a.size) && (aa-a).empty? }
  #=> true 

true 被返回,a 被拒绝。在最后一次计算中,d 的第一个元素被传递给块,并执行以下计算:

aa = [1, 6]
(aa.size < a.size)
  #=> 2 < 3 => true
(aa-a).empty?
  #=> ([1, 6] - [1, 3, 6]).empty? => [].empty? => true

作为true &amp;&amp; true #=&gt; truea ([1, 3, 6]) 被拒绝。

替代计算

以下是与 OP 的 Python 等效项更接近的匹配,但效率较低:

def remove_super_arrays(arr)
  arr.select do |a|
    (arr-[a]).all? { |aa| aa.size > a.size || (aa-a).any? }
  end
end

def remove_super_arrays(arr)
  arr.reject do |a|
    (arr-[a]).any? { |aa| (aa.size < a.size) && (aa-a).empty? }
  end
end

【讨论】:

  • 很好的答案和解释!
  • 对不起,这会改变我输入的数组还是创建一个新数组?
  • 返回一个新数组,保持原数组不变。
【解决方案2】:

这对我来说是一个很好的练习。我使用了here的逻辑。

我的代码遍历每个子数组(第一个除外),然后使用第一个索引进行魔术减法,当它为空时,另一个数组包含两个数字。

def remove_super_arrays(arr)
  arr.each_with_index.with_object([]) do |(sub_array, index), result|
    next if index == 0
    result << sub_array unless (arr.first - sub_array).empty?
  end.unshift(arr.first)
end
arr = [[1,6],[1,2],[2,4],[3,5],[1,3,6],[2,3,6]]   
p remove_super_arrays(arr)  
 #=> [[1, 6], [1, 2], [2, 4], [3, 5], [2, 3, 6]]

【讨论】:

  • 这不是保单,要求之一:remove_super_arrays [[1,2,4],[2,3,4],[1,4,5],[2,6]] #=&gt; [[2, 6], [1, 2, 4], [2, 3, 4], [1, 4, 5]]。将此与 OP 的第二个示例进行比较。
  • 你当然可以像我做的那样做:在开始时保存排序,然后在最后重新排序。还要考虑arr.each_with_index.with_object([]) do |(sub_array, index), result| ... 然后end.unshift(arr.first) 并删除result = []。好像还有一个问题:remove_super_arrays [[2], [1], [1,3]] #=&gt; [[2], [1], [1, 3]].
  • 谢谢,我已经用with_object part 更新了我的答案。其余的保持原样。我的意思是,这不是公认的答案,只是试图解决挑战。顺便说一句,您的个人资料中的电子邮件地址技巧不错:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-25
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多