2010-07-27 102 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 
相關問題