Example:
Here is binary numbers array:
a = [001, 010, 100, 011, 101, 110, 111, 1000, 1001, 1010]
I want output like below:
[ [ 001, 010, 100, 1000 ], [ 011, 101, 110, 1001, 1010 ], [ 111 ] ]
Can anybody help me how to achieve it in ruby?
Example:
Here is binary numbers array:
a = [001, 010, 100, 011, 101, 110, 111, 1000, 1001, 1010]
I want output like below:
[ [ 001, 010, 100, 1000 ], [ 011, 101, 110, 1001, 1010 ], [ 111 ] ]
Can anybody help me how to achieve it in ruby?
Using Enumerable#group_by
, as @Silvio has done, seems the most direct way to solve this problem, but here are a couple of other approaches one could use.
a = "001, 010, 100, 011, 101, 110, 111, 1000, 1001, 1010".split(', ')
#=> ["001", "010", "100", "011", "101", "110", "111", "1000", "1001", "1010"]
Construct a hash whose keys, k
, are numbers of ones and whose values are arrays containing the elements from the original array whose numbers of one1 equal k
a.each_with_object({}) { |s,h| (h[s.count('1')] ||= []) << s }.values
#=> [["001", "010", "100", "1000"], ["011", "101", "110", "1001", "1010"], ["111"]]
Note values
is applied to the hash returned by the block, namely
{1=>["001", "010", "100", "1000"], 2=>["011", "101", "110", "1001", "1010"], 3=>["111"]}
Consider the expression, (h[s.count('1')] ||= []) << s
. Let
cnt = s.count('1')
Then (h[cnt] ||= []) << s
expands to the following when parsed.
(h[cnt] = h[cnt] || []) << s
If h
does not have a key cnt
, then h[cnt]
on the right of the equality equals nil
, so the expression reduces to
(h[cnt] = []) << s
so h[cnt] #=> [s]
. On the other hand, if h
does have a key cnt
, h[cnt]
equals an array, which is truthy, so we execute
h[cnt] << s
Note that in h[cnt] = h[cnt] || []
, the method on the left of the equality is Hash#[]=, whereas we have Hash#[] is on the right of the equality.
Sort then slice
a.sort_by { |s| s.count('1') }.slice_when { |s1,s2| s1.count('1') < s2.count('1') }.to_a
#=> [["001", "010", "100", "1000"], ["011", "101", "110", "1001", "1010"], ["111"]]
I'm going to assume you're working with strings (
"001"
) and not decimal/octal literals (001
). If that's not the case, I strongly suggest casting to strings to make things easier on you.We can count the number of ones in a string
x
withx.count('1')
. Then we can take a list of strings and organize it by this value witha.group_by(...)
. This gives a hash, so if you just want the values (as your suggested output suggests), then you simply take thevalues
of it.