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

时间:2022-03-31 20:36:23

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

我有一个@horses =[]数组,其中填充了一些随机的马。

How can I check if my @horses array 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:

我也尝试过包含?但我只看到它是用于字符串的。存在吗?我得到了以下错误:

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?

所以问题是,我如何检查我的数组是否已经包含了"马"这样我就不能用相同的马填充它?

7 个解决方案

#1


160  

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

Ruby中的数组不存在吗?方法,但是它们有包含吗?方法如文档中所述。类似的

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

should work out of box.

应该是开箱即用。

#2


10  

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?并传递一个计算为真或假的块:

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

#3


3  

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

为什么不简单地从0到马选出8个不同的数呢?数数,用它来取你的马?

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#sample is 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,需要'backports'或者使用类似shuff .first(n)的东西。

#4


2  

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

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

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 redefined comparision operator for objects to take a look only for its state (new/created) and id

ActiveRecord为对象重新定义了comparision运算符,以便只查找其状态(新建/创建)和id

#5


1  

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

数组的包括什么?方法接受任何对象,而不仅仅是字符串。这应该工作:

@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

#6


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?

所以问题是,我如何检查我的数组是否已经包含了"马"这样我就不能用相同的马填充它?

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.

相反,可以使用散列或集合,两者都只允许一个特定元素的实例。Set的行为会更接近数组,但只允许一个实例。这是一种更先发制人的方法,避免重复,因为容器的性质。

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.

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

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)

#7


0  

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

#1


160  

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

Ruby中的数组不存在吗?方法,但是它们有包含吗?方法如文档中所述。类似的

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

should work out of box.

应该是开箱即用。

#2


10  

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?并传递一个计算为真或假的块:

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

#3


3  

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

为什么不简单地从0到马选出8个不同的数呢?数数,用它来取你的马?

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#sample is 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,需要'backports'或者使用类似shuff .first(n)的东西。

#4


2  

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

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

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 redefined comparision operator for objects to take a look only for its state (new/created) and id

ActiveRecord为对象重新定义了comparision运算符,以便只查找其状态(新建/创建)和id

#5


1  

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

数组的包括什么?方法接受任何对象,而不仅仅是字符串。这应该工作:

@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

#6


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?

所以问题是,我如何检查我的数组是否已经包含了"马"这样我就不能用相同的马填充它?

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.

相反,可以使用散列或集合,两者都只允许一个特定元素的实例。Set的行为会更接近数组,但只允许一个实例。这是一种更先发制人的方法,避免重复,因为容器的性质。

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.

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

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)

#7


0  

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