如何检查我的数组是否包含一个对象?
我有一个数组@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?
但我看到它只是用于string。 与exists?
我得到以下错误:
undefined method `exists?' for #<Array:0xc11c0b8>
所以问题是如何检查我的数组是否已经包含一个“马”,这样我就不用同一匹马来填充它了?
Ruby中的数组不exists?
方法。 他们有include?
方法在文档中描述 。 就像是
unless @suggested_horses.include?(horse) @suggested_horses << horse end
应该开箱即用。
如果你想检查对象是否在数组中,通过检查对象的属性,你可以使用any?
并传递一个评估为真或假的块:
unless @suggested_horses.any? {|h| h.id == horse.id } @suggested_horses << horse end
为什么不简单地通过从0
到Horse.count
select八个不同的数字,并使用它来获得你的马?
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版本)的新增function,因此升级您的Ruby, require 'backports'
或使用诸如shuffle.first(n)
类的东西。
#include?
应该工作,它适用于一般对象 ,不仅string。 示例代码中的问题是这个testing:
unless @suggested_horses.exists?(horse.id) @suggested_horses<< horse end
(甚至假设使用#include?
)。 您尝试search特定对象,而不是id。 所以应该是这样的:
unless @suggested_horses.include?(horse) @suggested_horses << horse end
ActiveRecord 重新定义了对象的运算符,只查看其状态(新build/创build)和id
arrays的include?
方法接受任何对象,而不仅仅是一个string。 这应该工作:
@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
-
Array#include?
文件
所以问题是如何检查我的数组是否已经包含一个“马”,这样我就不用同一匹马来填充它了?
虽然答案是关注通过数组来查看特定的string或对象是否存在,但事实上这是错误的,因为随着数组变大,search将花费更长的时间。
而是使用一个哈希或一个集合 。 两者都只允许一个特定元素的单个实例。 设置将更接近一个数组,但只允许一个实例。 由于容器的性质,这是一种更为先发制人的方法,避免了重复。
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"}>
哈希使用名称/值对,这意味着值将不会有任何实际用途,但似乎有一点额外的速度使用散列,基于一些testing。
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)
这个 …
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