1

The program should produce only unique aircraft, it repeats the element array. uniq method doesn't help.

class Airplane

    attr_accessor :model        

    def initialize(model) 
        @model = model
    end
end

models  =   [ "Boeing 777-300ER",
              "Boeing 737-800",
              "Airbus А330-200", 
              "Airbus А330-300",
              "Airbus А321",
              "Airbus A320",
              "Sukhoi SuperJet 100"]
planes = []

150.times do

    model = models[rand(0..6)]
    plane = Airplane.new(model)

    planes << plane 

try here # planes = planes.uniq doesn't help

    break if models.length == planes.length
end

# result
planes.uniq.each do |plane|   # <<<< uniq doesn't help
    puts "Model: #{plane.model}"
end
4
  • 1
    The strings in your list are all different — if you want to consider ones that share the part of the model before the hyphen to be the same, you need to make that explicit in code. Commented Sep 6, 2019 at 3:50
  • 2
    @Linuxios: That is irrelevant. uniq is called on the 150-element array of Airplane, not on the 7-element array of String. The issue is the lack of equality predicate on Airplane class. Commented Sep 6, 2019 at 3:53
  • %w [....] or "Boeing_777_300ER" underscore? Commented Sep 6, 2019 at 3:53
  • 1
    @Amadan: I wouldn't call it irrelevant; at some point a model string comparison will be needed, though you are of course right about Airplane#eql? being the first problem. Commented Sep 6, 2019 at 3:55

2 Answers 2

8

Unless specified otherwise, no two objects are the same:

Object.new.eql?(Object.new)
# => false

Thus, where #uniq is concerned, all 150 Airplane instances are unique, with no duplicates.

The easiest way to fix this is to provide the uniqueness criterion to #uniq:

planes.uniq(&:model)

The other way is to define what "duplicate" means for the Airplane class:

class Airplane
  attr_accessor :model        

  def initialize(model) 
    @model = model
  end

  def ==(other)
    other.class == self.class && other.model == self.model
  end

  alias_method :eql?, :==

  def hash
    self.model.hash
  end
end

However, this solution will make two airplanes of the same model the same airplane, in all cases, which might have unintended consequences in other places.

Sign up to request clarification or add additional context in comments.

9 Comments

Ruby: Why does #hash need to overridden whenever #eql? is overridden? (Same logic explained for Hash there holds for #uniq, whose docs explicitly mention #eql? and #hash are used.)
In the first way, just replace planes.uniq with planes.uniq(&:model) (e.g. planes.uniq(&:model).each ... in your third-from-last line). I don't know what you mean by "still displays elements 4 or 5".
planes = planes.uniq would become planes = planes.uniq(&:model), or planes.uniq!(&:model). That line is a bit misplaced - it will work there, but it is inefficient, the right place for that line would be after the loop. But then you have uniq twice - just use one or the other, there's no need to repeat it. And I still don't understand "still displays elements 4 or 5"...?
7 different planes models, and displays 3..6 unique planes output to be exact. break if models.length == planes.length maybe this is the length?
Ah, yes, sorry, I did not see that line, and did not test with it. I do not know what purpose it serves for you — you will break if you get 7 airplanes, which may be non-unique (if you moved the uniq line as I suggested earlier) and then #uniq will remove the dupes and give you less. I am not sure what result you are trying to get — I was only dealing with the #uniq problem.
|
0

You are comparing objects of a class, and each object is different even though they are of same instance type. You can override this behaviour by defining a comparison method for your class

class Aeroplane
    def ==(o)
      o.class == self.class && o.model == model
    end
end

1 Comment

This does not work; #uniq looks at #eql? (and #hash), not at #==.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.