【问题标题】:How do I check to see if my array includes an object?如何检查我的数组是否包含对象?
【发布时间】:2010-07-27 13:01:20
【问题描述】:

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

所以问题是如何检查我的数组是否已经包含“马”,这样我就不会用同一匹马填充它?

【问题讨论】:

标签: ruby-on-rails ruby


【解决方案1】:

Ruby 中的数组没有exists? 方法,但它们有一个include? 方法as described in the docs。 类似的东西

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

应该开箱即用。

【讨论】:

  • 这可能很糟糕,因为包括?将扫描整个数组并且是 n O(n) 的顺序
  • 它在时间上是线性的,它在每个项目上遍历列表一次。不过,挑剔性能没有任何意义。这是一个如此简单的案例。如果您关心快速查找,请使用来自std-libHashSet
  • 相反:除非 horse.in?(@suggested_horses) @suggested_horses
  • @Kush:同意,O(n) 并不理想。但是,如果我们短路,avg 的情况仍然是 O(n) ;) 最后,我们选择用 Ruby 编写(所有语言中......)
【解决方案2】:

如果你想通过检查对象的属性来检查对象是否在数组中,你可以使用any? 并传递一个判断为真或假的块:

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

【讨论】:

    【解决方案3】:

    #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

    【讨论】:

      【解决方案4】:

      为什么不简单地从0Horse.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) 的东西。

      【讨论】:

        【解决方案5】:

        所以问题是如何检查我的数组是否已经包含“马”,这样我就不会用同一匹马填充它?

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

        改为使用HashSet。两者都只允许特定元素的单个实例。 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"}>
        

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

        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)
        

        【讨论】:

          【解决方案6】:

          Array 的include?method 接受任何对象,而不仅仅是字符串。这应该有效:

          @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
          

          【讨论】:

            【解决方案7】:

            horses.include? new_horse 的替代品是new_horse.in? horses

            我不认为引擎盖下有太多(任何?)差异,但有时这样读起来会更好。特别是如果您希望第一个术语在阅读整个声明之前更多地解释正在发生的事情。例如,这个:

            [403, 404, 503].include? http_status 
            

            ...不像以下那样可读:

            http_status.in? [403, 404, 503]
            

            【讨论】:

              猜你喜欢
              • 2020-06-07
              • 2020-08-09
              • 1970-01-01
              • 1970-01-01
              • 2019-07-26
              • 2012-12-04
              • 1970-01-01
              • 2021-12-21
              • 2015-01-24
              相关资源
              最近更新 更多