Ruby-on-rails 如何检查我的数组是否包含对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3343861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:57:54  来源:igfitidea点击:

How do I check to see if my array includes an object?

ruby-on-railsruby

提问by necker

I have an array @horses = []that I fill with some random horses.

我有一个@horses = []用一些随机马填充的数组。

How can I check if my @horsesarray includes a horse that is already included (exists) in it?

如何检查我的@horses阵列是否包含已包含(存在)的马?

I tried something like:

我试过类似的东西:

@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

I also tried with include?but I saw it was for strings only. With exists?I get the following error:

我也尝试过,include?但我看到它仅适用于字符串。随着exists?我得到以下错误:

undefined method `exists?' for #<Array:0xc11c0b8>

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?

所以问题是如何检查我的阵列是否已经包含一匹“马”,以便我不会用同一匹马填充它?

回答by Tomasz Cudzi?o

Arrays in Ruby don't have exists?method, but they have an include?method as described in the docs. Something like

Ruby 中的数组没有exists?方法,但它们有docs 中描述include?方法。就像是

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

should work out of box.

应该开箱即用。

回答by Andrew

If you want to check if an object is within in array by checking an attribute on the object, you can use any?and pass a block that evaluates to true or false:

如果您想通过检查对象上的属性来检查对象是否在数组中,您可以使用any?并传递一个计算结果为 true 或 false 的块:

unless @suggested_horses.any? {|h| h.id == horse.id }
  @suggested_horses << horse
end

回答by Marc-André Lafortune

Why not do it simply by picking eight different numbers from 0to Horse.countand use that to get your horses?

为什么不简单地从0to 中选择八个不同的数字Horse.count并用它来得到你的马呢?

offsets = (0...Horse.count).to_a.sample(8)
@suggested_horses = offsets.map{|i| Horse.first(:offset => i) }

This has the added advantage that it won't cause an infinite loop if you happen to have less than 8 horses in your database.

这有一个额外的好处,即如果您的数据库中的马数少于 8 匹,则不会导致无限循环。

Note:Array#sampleis new to 1.9 (and coming in 1.8.8), so either upgrade your Ruby, require 'backports'or use something like shuffle.first(n).

注意:Array#sample是 1.9 的新版本(并且在 1.8.8 中推出),所以要么升级你的 Ruby,require 'backports'要么使用类似shuffle.first(n).

回答by MBO

#include?should work, it works for general objects, not only strings. Your problem in example code is this test:

#include?应该有效,它适用于一般对象,而不仅仅是字符串。您在示例代码中的问题是这个测试:

unless @suggested_horses.exists?(horse.id)
  @suggested_horses<< horse
end

(even assuming using #include?). You try to search for specific object, not for id. So it should be like this:

(即使假设使用#include?)。您尝试搜索特定对象,而不是 id。所以它应该是这样的:

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

ActiveRecord has redefinedcomparision operator for objects to take a look only for its state (new/created) and id

ActiveRecord重新定义了对象的比较运算符,以便仅查看其状态(新建/创建)和 id

回答by the Tin Man

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?

所以问题是如何检查我的阵列是否已经包含一匹“马”,以便我不会用同一匹马填充它?

While the answers are concerned with looking through the array to see if a particular string or object exists, that's really going about it wrong, because, as the array gets larger, the search will take longer.

虽然答案与查看数组以查看特定字符串或对象是否存在有关,但这确实是错误的,因为随着数组变大,搜索将花费更长的时间。

Instead, use either a Hash, or a Set. Both only allow a single instance of a particular element. Set will behave closer to an Array but only allows a single instance. This is a more preemptive approach which avoids duplication because of the nature of the container.

相反,使用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"}>

Hash uses name/value pairs, which means the values won't be of any real use, but there seems to be a little bit of extra speed using a Hash, based on some tests.

Hash 使用名称/值对,这意味着这些值不会有任何实际用途,但根据一些测试,使用 Hash 似乎有一点额外的速度。

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

Which outputs:

哪些输出:

            user     system      total        real
Hash    8.140000   0.130000   8.270000 (  8.279462)
Array  10.680000   0.120000  10.800000 ( 10.813385)

回答by John Topley

Array's include?method accepts any object, not just a string. This should work:

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

回答by Chris McCauley

This ...

这个 ...

horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.exists?(horse.id)
   @suggested_horses<< horse
end

Should probably be this ...

应该是这个...

horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.include?(horse)
   @suggested_horses<< horse
end