Ruby on rails 如何确定一个数组是否包含另一个数组的所有元素
鉴于: 我想确定它是否包含以下所有元素:Ruby on rails 如何确定一个数组是否包含另一个数组的所有元素,ruby-on-rails,arrays,ruby,Ruby On Rails,Arrays,Ruby,鉴于: 我想确定它是否包含以下所有元素: a1 = [5, 1, 6, 14, 2, 8] 在这种情况下,结果为false 是否有任何内置的Ruby/Rails方法来识别这样的数组包含 实现这一点的一种方法是: a2 = [2, 6, 15] 有更好、更可读的方法吗?也许这更容易阅读: a2.index{ |x| !a1.include?(x) }.nil? 也可以使用阵列交点: a2.all? { |e| a1.include?(e) } 请注意,此处使用的size仅用于速度,您也可以
a1 = [5, 1, 6, 14, 2, 8]
在这种情况下,结果为false
是否有任何内置的Ruby/Rails方法来识别这样的数组包含
实现这一点的一种方法是:
a2 = [2, 6, 15]
有更好、更可读的方法吗?也许这更容易阅读:
a2.index{ |x| !a1.include?(x) }.nil?
也可以使用阵列交点:
a2.all? { |e| a1.include?(e) }
请注意,此处使用的size
仅用于速度,您也可以执行(较慢):
但我想第一个更具可读性。这3个是纯ruby(不是rails)。这可以通过
(a1 & a2) == a1
这将创建两个数组的交集,返回a2
中的所有元素,这些元素也位于a1
中。如果结果与a2
相同,则可以确保a1
中包含所有元素
这种方法仅在
a2
中的所有元素首先彼此不同时才有效。如果出现双重情况,这种方法将失败。Tempos的方法仍然有效,因此我衷心推荐他的方法(也可能更快)。如果没有重复的元素或者您不关心它们,那么您可以使用该类:
在幕后,这使用
a1 = Set.new [5, 1, 6, 14, 2, 8]
a2 = Set.new [2, 6, 15]
a1.subset?(a2)
=> false
根据你的数组有多大,你可以考虑一个高效的算法O(nlog n)
排序代价O(n logn),检查每对代价O(n),因此该算法是O(n logn)。使用未排序的数组,其他算法不能更快(渐进地)。您可以对数组类进行monkey-patch:
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
试验
当然,该方法可以单独编写为标准方法,例如
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
你可以像这样调用它
def contains_all?(a,b)
b.uniq.all? { |x| a.count(x) >= b.count(x) }
end
事实上,在分析之后,下面的版本速度更快,代码更短
contains_all?(%w[a b c c], %w[c c c])
如果两个数组中都有重复的元素,那么基于(a1-a2)或(a1&a2)的大多数答案都不起作用。我来到这里是想看看一个单词的所有字母(拆分成一个数组)是否都是一组字母的一部分(例如拼字)。这些答案都不管用,但这一个确实管用:
def contains_all?(a,b)
b.all? { |x| a.count(x) >= b.count(x) }
end
def包含所有内容?(a1、a2)
try=1.chars.all?不信|
a1.count(letter)当我试图找出一个数组[“a”、“b”、“c”]
是否包含另一个数组[“a”、“b”]
时,就我而言,相同的顺序是这个问题的额外要求
以下是我的解决方案(我相信这是O(n)复杂性),适用于任何有额外需求的人:
def array_包括_array(array_to_inspect,array_to_search)
inspectLength=数组\u到\u inspect.length
searchLength=array\u to\u search\u for.length
如果searchLength==0,则
返回真值
结束
如果searchLength>inspectLength,则
返回错误
结束
缓冲区=[]
对于长度为0的i
buffer.push(数组到检查[i])
bufferLastIndex=buffer.length-1
如果(buffer[bufferLastIndex]!=数组搜索[bufferLastIndex]),则
缓冲区,清除
下一个
结束
如果(buffer.length==searchLength),则
返回真值
结束
结束
返回错误
结束
这将产生测试结果:
将“1:{array_包括_array([“a”,“b”,“c”],[“b”,“c”])}”置为true
将“2:{array_包括_array([“a”,“b”,“c”],[“a”,“b”])}”)置为true
将“3:{array_包括_array([“a”,“b”,“c”],[“b”,“b”])}”置为“false”
将“4:{array_包括_array([“a”,“b”,“c”],[“c”,“b”,“a”])}”置为“false”
将“5:{array_包括_array([“a”、“b”、“c”],[])}”)置为true
将“6:#{array_包括_array([],[“a”])}”置为“false”
将“7:#{array_包括_array([],[])}”置为true
这就是我们要走的路。它可能只是稍微缩短为(a2-a1)。为空?
这只适用于集合数组,而不适用于具有集合的数组duplicates@Chris-您可以尝试使用Array#uniq。以霍尔格为例,它应该是(a2.uniq-a1.uniq)。空?
就是我的意思。数组#unique将显式失败。使用length
方法将执行得更好如果交集具有不同顺序的相同元素,则此方法将不起作用。当我试图回答这个问题时,我发现了这一点:后来我意识到很多聪明人已经在这里做到了@古巴很有趣。你有一些测试数据来重现这个吗?在我的测试中,结果数组似乎保留了第一个数组中元素的顺序(因此我最近对答案进行了编辑)。然而,如果事实并非如此,我想学习。@HolgerJust我犯了错误,做了(a1&a2)而不是(a2&a1),这就是我看到错误的原因。关于保留第一个数组的顺序,您是对的。您可以使用计数排序在O(n)中执行此操作。不,您不能。计数排序使用有限的范围,Ruby对大数的获取没有限制。您可以,因为您实际上不必对项进行排序-您只需要两个数组的哈希映射项-->计数,然后迭代键并比较计数。你确定数组#sort使用合并排序吗?如果使用OP对a1和a2的定义,并且a1“包含”a2的所有元素,我认为这应该是(a1和a2)。size==a2.size,因为a2是较小的数组,它应该包含较大数组中的所有元素(以获得“true”)-因此,如果两个数组中的所有元素都存在于较大数组中,则两个数组的交集应与较小数组的长度相同。可接受的答案(数组减法)是最快的解决方案。我在这里对它们进行了基准测试:
class Array
def contains_all?(ary)
ary.uniq.all? { |x| count(x) >= ary.count(x) }
end
end
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
def contains_all?(a,b)
b.uniq.all? { |x| a.count(x) >= b.count(x) }
end
contains_all?(%w[a b c c], %w[c c c])
def contains_all?(a,b)
b.all? { |x| a.count(x) >= b.count(x) }
end
def contains_all?(a1, a2)
try = a1.chars.all? do |letter|
a1.count(letter) <= a2.count(letter)
end
return try
end