Uniq的ruby数组无法正常工作

Ste*_*eve 2 ruby arrays distinct

我有一个我的对象Country的数组,它具有"代码"和"名称"的属性

该阵列可能不止一次有一个国家,所以我想区分数组.

这是我的国家级

class Country
  include Mongoid::Fields::Serializable
  attr_accessor :name, :code

  FILTERS = ["Afghanistan","Brunei","Iran", "Kuwait", "Libya", "Saudi Arabia", "Sudan", "Yemen", "Britain (UK)", "Antarctica", "Bonaire Sint Eustatius & Saba", "British Indian Ocean Territory", "Cocos (Keeling) Islands", "St Barthelemy", "St Martin (French part)", "Svalbard & Jan Mayen","Vatican City"]

  EXTRAS = {
    'eng' => 'England',
    'wal' => 'Wales',
    'sco' => 'Scotland',
    'nlr' => 'Northern Ireland'
    }

  def initialize(name, code)
    @name = name
    @code = code
  end

  def deserialize(object)
    return nil unless object
    Country.new(object['name'], object['code'])
  end

  def serialize(country)
    {:name => country.name, :code => country.code}
  end

  def self.all
    add_extras(filter(TZInfo::Country.all.map{|country| to_country country})).sort! {|c1, c2| c1.name <=> c2.name}
  end

  def self.get(code)
    begin
      to_country TZInfo::Country.get(code)
    rescue TZInfo::InvalidCountryCode => e
      'InvalidCountryCode' unless EXTRAS.has_key? code
      Country.new EXTRAS[code], code
    end
  end

  def self.get_by_name(name)
    all.select {|country| country.name.downcase == name.downcase}.first
  end

  def self.filter(countries)
    countries.reject {|country| FILTERS.include?(country.name)}
  end

  def self.add_extras(countries)
    countries + EXTRAS.map{|k,v| Country.new v, k}
  end

  private
  def self.to_country(country)
    Country.new country.name, country.code
  end
end
Run Code Online (Sandbox Code Playgroud)

和我对从另一个类调用的数组的请求

  def countries_ive_drunk
    (had_drinks.map {|drink| drink.beer.country }).uniq
  end
Run Code Online (Sandbox Code Playgroud)

如果我抛出数组,我可以看到结构是:

[
#<Country:0x5e3b4c8 @name="Belarus", @code="BY">, 
#<Country:0x5e396e0 @name="Britain (UK)", @code="GB">, 
#<Country:0x5e3f350 @name="Czech Republic", @code="CZ">, 
#<Country:0x5e3d730 @name="Germany", @code="DE">, 
#<Country:0x5e43778 @name="United States", @code="US">, 
#<Country:0x5e42398 @name="England", @code="eng">, 
#<Country:0x5e40f70 @name="Aaland Islands", @code="AX">, 
#<Country:0x5e47978 @name="England", @code="eng">, 
#<Country:0x5e46358 @name="Portugal", @code="PT">, 
#<Country:0x5e44d38 @name="Georgia", @code="GE">, 
#<Country:0x5e4b668 @name="Germany", @code="DE">, 
#<Country:0x5e4a2a0 @name="Anguilla", @code="AI">, 
#<Country:0x5e48c98 @name="Anguilla", @code="AI">
]
Run Code Online (Sandbox Code Playgroud)

这是一样的,无论我是否.uniq,你可以看到有两个"安圭拉"

Mar*_*une 5

正如其他人所指出的那样,问题在于uniq用于hash区分国家和默认情况下Object#hash的所有对象都是不同的.它还将用于eql?以防两个对象返回相同的hash值,以确定它们是否为eql.

最好的解决方案是让您的课程正确!

class Country
  # ... your previous code, plus:

  include Comparable

  def <=>(other)
    return nil unless other.is_a?(Country)
    (code <=> other.code).nonzero? || (name <=> other.name)
    # or less fancy:
    #   [code, name] <=> [other.code, other.name]
  end

  def hash
    [name, code].hash
  end

  alias eql? ==
end

Country.new("Canada", "CA").eql?(Country.new("Canada", "CA")) # => true
Run Code Online (Sandbox Code Playgroud)

现在你可以对国家数组进行排序,使用国家作为哈希的关键,比较它们等等......

我已经包含了上面的代码,以显示它是如何完成的,但在你的情况下,如果你继承了,你可以免费获得所有这些Struct(:code, :name)...

class Country < Stuct(:name, :code)
  # ... the rest of your code, without the `attr_accessible` nor the `initialize`
  # as Struct provides these and `hash`, `eql?`, `==`, ...
end
Run Code Online (Sandbox Code Playgroud)