Ruby-on-rails 如何确定一个数组是否包含另一个数组的所有元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7387937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 01:57:46  来源:igfitidea点击:

How to determine if one array contains all elements of another array

ruby-on-railsarraysruby

提问by Misha Moroshko

Given:

鉴于:

a1 = [5, 1, 6, 14, 2, 8]

I would like to determine if it contains all elements of:

我想确定它是否包含以下所有元素:

a2 = [2, 6, 15]

In this case the result is false.

在这种情况下,结果是false

Are there any built-in Ruby/Rails methods to identify such array inclusion?

是否有任何内置的 Ruby/Rails 方法来识别此类数组包含?

One way to implement this is:

实现这一点的一种方法是:

a2.index{ |x| !a1.include?(x) }.nil?

Is there a better, more readable, way?

有没有更好、更易读的方法?

回答by Geo

a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
=> [5, 1, 14, 8]

b - a
=> [15]

(b - a).empty?
=> false

回答by Pablo Fernandez

Perhaps this is easier to read:

也许这更容易阅读:

a2.all? { |e| a1.include?(e) }

You can also use array intersection:

您还可以使用数组交集:

(a1 & a2).size == a1.size

Note that sizeis used here just for speed, you can also do (slower):

请注意,size这里仅用于速度,您也可以这样做(更慢):

(a1 & a2) == a1

But I guess the first is more readable. These 3 are plain ruby (not rails).

但我想第一个更具可读性。这 3 个是普通的红宝石(不是导轨)。

回答by Holger Just

This can be achieved by doing

这可以通过做

(a2 & a1) == a2

This creates the intersection of both arrays, returning all elements from a2which are also in a1. If the result is the same as a2, you can be sure you have all elements included in a1.

这将创建两个数组的交集,返回a2其中也在 中的所有元素a1。如果结果与 相同a2,则可以确定所有元素都包含在a1.

This approach only works if all elements in a2are different from each other in the first place. If there are doubles, this approach fails. The one from Tempos still works then, so I wholeheartedly recommend his approach (also it's probably faster).

这种方法仅适用于所有元素a2最初彼此不同的情况。如果有双打,这种方法就失败了。来自 Tempos 的那个仍然有效,所以我全心全意地推荐他的方法(而且它可能更快)。

回答by Confusion

If there are are no duplicate elements or you don't care about them, then you can use the Setclass:

如果没有重复的元素或者你不关心它们,那么你可以使用Set类:

a1 = Set.new [5, 1, 6, 14, 2, 8]
a2 = Set.new [2, 6, 15]
a1.subset?(a2)
=> false

Behind the scenes this uses

这在幕后使用

all? { |o| set.include?(o) }

回答by Zack Xu

You can monkey-patch the Array class:

您可以对 Array 类进行猴子补丁:

class Array
    def contains_all?(ary)
        ary.uniq.all? { |x| count(x) >= ary.count(x) }
    end
end

test

测试

irb(main):131:0> %w[a b c c].contains_all? %w[a b c]
=> true
irb(main):132:0> %w[a b c c].contains_all? %w[a b c c]
=> true
irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c]
=> false
irb(main):134:0> %w[a b c c].contains_all? %w[a]
=> true
irb(main):135:0> %w[a b c c].contains_all? %w[x]
=> false
irb(main):136:0> %w[a b c c].contains_all? %w[]
=> true
irb(main):137:0> %w[a b c d].contains_all? %w[d c h]
=> false
irb(main):138:0> %w[a b c d].contains_all? %w[d b c]
=> true

Of course the method can be written as a standard-alone method, eg

当然,该方法可以编写为标准的单独方法,例如

def contains_all?(a,b)
    b.uniq.all? { |x| a.count(x) >= b.count(x) }
end

and you can invoke it like

你可以像这样调用它

contains_all?(%w[a b c c], %w[c c c])

Indeed, after profiling, the following version is much faster, and the code is shorter.

确实,经过profiling,下面这个版本速度快了很多,代码也更短了。

def contains_all?(a,b)
    b.all? { |x| a.count(x) >= b.count(x) }
end

回答by Charles Breton

Most answers based on (a1 - a2) or (a1 & a2) would not work if there are duplicate elements in either array. I arrived here looking for a way to see if all letters of a word (split to an array) were part of a set of letters (for scrabble for example). None of these answers worked, but this one does:

如果任一数组中存在重复元素,大多数基于 (a1 - a2) 或 (a1 & a2) 的答案将不起作用。我来到这里寻找一种方法来查看单词的所有字母(拆分为数组)是否是一组字母的一部分(例如拼字游戏)。这些答案都没有奏效,但这个答案确实有效:

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end

回答by ayckoster

Depending on how big your arrays are you might consider an efficient algorithm O(n log n)

根据你的数组有多大,你可能会考虑一个有效的算法 O(n log n)

def equal_a(a1, a2)
  a1sorted = a1.sort
  a2sorted = a2.sort
  return false if a1.length != a2.length
  0.upto(a1.length - 1) do 
    |i| return false if a1sorted[i] != a2sorted[i]
  end
end

Sorting costs O(n log n) and checking each pair costs O(n) thus this algorithm is O(n log n). The other algorithms cannot be faster (asymptotically) using unsorted arrays.

排序成本 O(n log n) 并检查每对成本 O(n) 因此该算法是 O(n log n)。使用未排序的数组,其他算法不能更快(渐近)。