如何检查我的数组是否包含一个对象?

我有一个数组@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 

为什么不简单地通过从0Horse.countselect八个不同的数字,并使用它来获得你的马?

 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