2010-07-27 105 views
65

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

这个问题是,如果这个问题间没有一个https://stackoverflow.com/questions/1529986/ruby-methods-equivalent-of-if-a-in-list-in-python重复从Python的角度来看, – 2017-07-29 02:37:19

回答

156

阵列在Ruby中一看没有exists?方法。他们得到了include?方法as described in docs。 类似于

unless @suggested_horses.include?(horse) 
    @suggested_horses << horse 
end 

应该开箱即用。

+1

这可能是不好的,因为包括?将扫描整个阵列并且是n的顺序O(n) – Kush 2014-04-02 09:24:03

+6

它在时间上是线性的,它在每个项目上经历一次列表。尽管如此,挑剔性能没有任何意义。这是一个简单的例子。如果您关心快速查找,请使用['Hash'](http://www.ruby-doc.org/core-2.1.1/Hash.html)或['Set'](http://www.ruby -doc.org/stdlib-2.1.1/libdoc/set/rdoc/Set.html)来自'std-lib'。 – 2014-04-08 11:26:46

+2

相反: 除非horse.in?(@suggested_horses) @suggested_horses << horse end – 2014-12-29 20:08:15

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 
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比较运营商为对象,只需要为它的状态(新/创建)和ID

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 
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)

1

So the question is how can I check if my array already has a "horse" included so that I don't fill it with the same horse?

虽然答案关心翻翻阵列,看是否有特定的字符串或对象是否存在,这真的是绕了错误的,因为,作为数组越大,搜索将需要更长的时间。可以使用HashSet。两者都只允许一个特定元素的单个实例。 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) 
10

如果要检查是否一个目的是在阵列内通过检查对象上的属性,可以使用any?并传递评估为真或嵌段假:

unless @suggested_horses.any? {|h| h.id == horse.id } 
    @suggested_horses << horse 
end 
相关问题