我有一个数组@horses = []
,我填充了一些随机马。
如何检查我的@horses
数组是否包含已包含(存在)的马?
我尝试过类似的事情:
@suggested_horses = []
@suggested_horses << Horse.find(:first,:offset=>rand(Horse.count))
while @suggested_horses.length < 8
horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.exists?(horse.id)
@suggested_horses<< horse
end
end
我也试过了include?
,但我看到它仅用于字符串。使用exists?
我收到以下错误:
undefined method `exists?' for #<Array:0xc11c0b8>
所以问题是如何检查我的阵列是否已经包含了“马”,以便我不会用同一匹马填充它?
答案 0 :(得分:170)
Ruby中的数组没有exists?
方法,但它们有include?
方法as described in the docs。
像
unless @suggested_horses.include?(horse)
@suggested_horses << horse
end
应该开箱即用。
答案 1 :(得分:13)
如果要通过检查对象上的属性来检查对象是否在数组中,可以使用any?
并传递一个计算结果为true或false的块:
unless @suggested_horses.any? {|h| h.id == horse.id }
@suggested_horses << horse
end
答案 2 :(得分:3)
为什么不通过从0
到Horse.count
中挑选八个不同的数字并使用它来获取您的马匹呢?
offsets = (0...Horse.count).to_a.sample(8)
@suggested_horses = offsets.map{|i| Horse.first(:offset => i) }
这样做的另一个好处是,如果您的数据库中碰巧少于8匹马,它不会导致无限循环。
注意: Array#sample
是1.9的新手(并且是1.8.8版),因此升级您的Ruby,require 'backports'
或使用shuffle.first(n)
之类的内容
答案 3 :(得分:2)
#include?
应该有用,它适用于general objects,而不仅仅是字符串。您在示例代码中的问题是此测试:
unless @suggested_horses.exists?(horse.id)
@suggested_horses<< horse
end
(即使假设使用#include?
)。您尝试搜索特定对象,而不是id。所以它应该是这样的:
unless @suggested_horses.include?(horse)
@suggested_horses << horse
end
ActiveRecord有redefined比较运算符,用于查看对象的状态(new / created)和id
答案 4 :(得分:1)
Array的include?
方法接受任何对象,而不仅仅是字符串。这应该有效:
@suggested_horses = []
@suggested_horses << Horse.first(:offset => rand(Horse.count))
while @suggested_horses.length < 8
horse = Horse.first(:offset => rand(Horse.count))
@suggested_horses << horse unless @suggested_horses.include?(horse)
end
答案 5 :(得分:1)
所以问题是如何检查我的阵列是否已经包含了“马”,以便我不会用同一匹马填充它?
虽然答案涉及通过查看数组以查看特定字符串或对象是否存在,但这确实是错误的,因为随着数组变大,搜索将花费更长时间。
相反,请使用Hash或Set。两者都只允许特定元素的单个实例。 Set将表现得更接近Array,但只允许单个实例。这是一种更具先发制人的方法,由于容器的性质,避免了重复。
hash = {}
hash['a'] = nil
hash['b'] = nil
hash # => {"a"=>nil, "b"=>nil}
hash['a'] = nil
hash # => {"a"=>nil, "b"=>nil}
require 'set'
ary = [].to_set
ary << 'a'
ary << 'b'
ary # => #<Set: {"a", "b"}>
ary << 'a'
ary # => #<Set: {"a", "b"}>
哈希使用名称/值对,这意味着这些值不会有任何实际用途,但基于某些测试,使用哈希似乎有一点额外的速度。
require 'benchmark'
require 'set'
ALPHABET = ('a' .. 'z').to_a
N = 100_000
Benchmark.bm(5) do |x|
x.report('Hash') {
N.times {
h = {}
ALPHABET.each { |i|
h[i] = nil
}
}
}
x.report('Array') {
N.times {
a = Set.new
ALPHABET.each { |i|
a << i
}
}
}
end
哪个输出:
user system total real
Hash 8.140000 0.130000 8.270000 ( 8.279462)
Array 10.680000 0.120000 10.800000 ( 10.813385)
答案 6 :(得分:0)
这......
horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.exists?(horse.id)
@suggested_horses<< horse
end
应该是这个......
horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.include?(horse)
@suggested_horses<< horse
end