1

I have an array and it looks like this: [7, 2, 3, 2, 2, 1]. As you can see there are three elements in this array with the integer value of 2. I want to take this array and create an index that will look something like this: { 1 => 1, 2 => 3, 3 => 1, 4 => 0, 5 => 0, 6 => 0, 7 => 1 }

So, basically a bar chart/histogram/index of a how many duplicates there are in the array.

Just for a high level view of this. I'm trying to find all of the unique emails for each account within my application.

3 Answers 3

3
a = [7, 2, 3, 2, 2, 1]    
1.upto(a.max).each_with_object({}) {|number, hash| hash[number] = a.count(number)}
#=> {1=>1, 2=>3, 3=>1, 4=>0, 5=>0, 6=>0, 7=>1}
Sign up to request clarification or add additional context in comments.

5 Comments

Calling count for each element of an array or enumerator should sound a warning bell (perhaps accompanied by the flashing message, "Inefficient! Ugly!"). Two alternatives that require only a single pass through the array are always available: construct a counting hash (Hash.new(0)) or use Enumerable#group_by.
@CarySwoveland as usually, good point, I thought of group_by from the beginning, but it didn't perfectly fit the OP's needs..
@Bitwise see Cary's answer for more efficient way of achieving the expected reslult
@EricDuminil I can't tell, since I have no idea what OP's trying to achieve ultimately. Being able to correctly word the question is essential in terms of getting the appropriate help. I showed the OP how to achieve exactly the result he has put as the desired one.
@AndreyDeineko: I agree the question is a bit confusing. The "real" question is in the last sentence IMHO (get unique email addresses), the middle question with example is just a way the OP thinks he can solve the last question.
1

Solution

This variant should be much faster than the other answers and will work for any array :

def histogram(array)
  array.each_with_object( Hash.new(0) ){|number, count| count[number] += 1 }
end

array = [7, 2, 3, 2, 2, 1, 'a', 'b', 'c', 'b']

p freq = histogram(array)
#=> {7=>1, 2=>3, 3=>1, 1=>1, "a"=>1, "b"=>2, "c"=>1}

p array.select{|number| freq[number] == 1}
#=> [7, 3, 1, "a", "c"]

Notes

element => 0

If I understand your question correctly, you don't need the 4 => 0, 5 => 0, 6 => 0 part in your Hash if all you want to do is to find elements that only appear once.

The information is here if you want to get it, though :

p freq[6]
#=> 0

SQL ?

If your array comes from a database via ActiveRecord, it might be a better idea to find the unique elements directly with a SQL query instead of retrieving all elements and applying logic to it.

Comments

0
arr = [8, 3, 4, 3, 3, 2]

min, max = arr.minmax
  #=> [2, 8] 
arr.each_with_object((min..max).to_a.product([0]).to_h) { |n,h| h[n] += 1 }
  #=> {2=>1, 3=>3, 4=>1, 5=>0, 6=>0, 7=>0, 8=>1}

Note:

(min..max).to_a.product([0]).to_h
  #=> {2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0, 8=>0}

1 Comment

Note that the "real" question is about email addresses. For ['[email protected]', '[email protected]'], your method creates 11863801 arrays!

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.