我有一个值“狗”和一个数组[“猫”、“狗”、“鸟”]。
如何在不循环的情况下检查数组中是否存在它?是否有一种简单的方法来检查该值是否存在?
我有一个值“狗”和一个数组[“猫”、“狗”、“鸟”]。
如何在不循环的情况下检查数组中是否存在它?是否有一种简单的方法来检查该值是否存在?
当前回答
还有一种方法可以做到这一点:
arr = ['Cat', 'Dog', 'Bird']
e = 'Dog'
present = arr.size != (arr - [e]).size
其他回答
如果不想循环,则无法使用数组进行循环。您应该改用Set。
require 'set'
s = Set.new
100.times{|i| s << "foo#{i}"}
s.include?("foo99")
=> true
[1,2,3,4,5,6,7,8].to_set.include?(4)
=> true
设置在内部像Hashes一样工作,因此Ruby不需要在集合中循环查找项,因为顾名思义,它会生成键的哈希值,并创建内存映射,以便每个哈希值指向内存中的某个点。前面的示例使用Hash完成:
fake_array = {}
100.times{|i| fake_array["foo#{i}"] = 1}
fake_array.has_key?("foo99")
=> true
缺点是Set和Hash键只能包含唯一的项,如果你添加了很多项,Ruby将不得不在一定数量的项之后重新散列整个项,以构建适合更大键空间的新映射。有关这方面的更多信息,我建议您观看“MountainWest RubyConf 2014-Nathan Long自制哈希中的大O”。
这里有一个基准:
require 'benchmark'
require 'set'
array = []
set = Set.new
10_000.times do |i|
array << "foo#{i}"
set << "foo#{i}"
end
Benchmark.bm do |x|
x.report("array") { 10_000.times { array.include?("foo9999") } }
x.report("set ") { 10_000.times { set.include?("foo9999") } }
end
结果是:
user system total real
array 7.020000 0.000000 7.020000 ( 7.031525)
set 0.010000 0.000000 0.010000 ( 0.004816)
如果你不想使用include?您可以首先将元素包装在数组中,然后检查包装的元素是否等于数组和包装的元素的交集。这将返回一个基于相等的布尔值。
def in_array?(array, item)
item = [item] unless item.is_a?(Array)
item == array & item
end
在任何数组中查找元素有多种方法,但最简单的方法是“in?”方法
example:
arr = [1,2,3,4]
number = 1
puts "yes #{number} is present in arr" if number.in? arr
这不仅会告诉你它存在,还会告诉你它出现的次数:
a = ['Cat', 'Dog', 'Bird']
a.count("Dog")
#=> 1
有几个答案建议阵列#包括?,但有一个重要的警告:查看源代码,甚至是Array#include?确实执行循环:
rb_ary_includes(VALUE ary, VALUE item)
{
long i;
for (i=0; i<RARRAY_LEN(ary); i++) {
if (rb_equal(RARRAY_AREF(ary, i), item)) {
return Qtrue;
}
}
return Qfalse;
}
在不循环的情况下测试单词存在的方法是为数组构造一个trie。有很多trie实现(谷歌“ruby trie”)。我将在本例中使用随机trie:
a = %w/cat dog bird/
require 'rambling-trie' # if necessary, gem install rambling-trie
trie = Rambling::Trie.create { |trie| a.each do |e| trie << e end }
现在,我们已经准备好测试数组中各种单词的存在,而无需在O(log n)时间内对其进行循环,语法简单性与array#include?,使用子线Trie#include?:
trie.include? 'bird' #=> true
trie.include? 'duck' #=> false