averiguar qué objeto tiene n instancias en Ruby

I have an array: x = [a, b, c, d, e, f, g, h] which can have objects from 1 to 9

Firstly, I have to count IF any of these objects is present 3 times. I don't want to write

if (x.count(1) == 3) or (x.count(2) == 3) ...etc... 

is there a way to shorten this, like below?

x.count { |obj| obj } == 3 

Secondly, if I know that an object has been found with 3 instances, how can I find out which one was it? (1 or 2 or 3.....)

preguntado el 28 de agosto de 12 a las 14:08

1 Respuestas

x = [:a, :b, :b, :b, :c, :c, :c]
counted = Hash[
  x.group_by do |e|
    x.count(e)
  end.map do |count, items|
    [count, items.uniq]
  end
]
p counted[3]    #=> [:b, :c]

How does this work? Let's follow the steps. First, let's group the items by count:

grouped_by_count = x.group_by do |e|
  x.count(e)
end

This produces a hash with the keys being the counts, and the values being the list of non-unique items having that count:

p grouped_by_count
#=> {1=>[:a], 3=>[:b, :b, :b, :c, :c, :c]}

We'd really rather have único items, though, so let's do that transform:

grouped_by_count_unique = grouped_by_count.map do |count, items|
  [count, items.uniq]
end
p grouped_by_count_unique
#=> [[1, [:a]], [3, [:b, :c]]]

That gives us an array of arrays, and not a hash. Fortunately, it's easy to turn an array of arrays into a hash:

counted = Hash[grouped_by_count_unique]
p counted
# => {1=>[:a], 3=>[:b, :c]}

Now just put the pieces together eliminating the temporaries and you get the answer at the top.

Respondido 28 ago 12, 15:08

Brilliant, thanks, it is very elegant too! I'll meditate on it. - csikiati

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.