-1

I have been staring at the following array of arrays for a few hours now and any combination of merge, select, find, map, flatten, etc., has not been able to help me yet.

I created some ugly nested loops, but nothing coming close to the Ruby way.

I have an array of arrays:

[
["Ja", nil, "Bijna", nil, "Ja"],
["Nee", nil, "Nee", "Ja", "Nee"],
[nil, nil, "Bijna", "Nee", "Nee"],
["Ja", nil, nil, "Nee", "Ja"],
["Bijna", nil, "Bijna", "Nee", "Ja"]
]

I need to count all the instances of the values vertically, yielding a hash of hashes like this:

{
{"Ja" => 2, "Nee" => 2, => "Bijna" => 1, "nil" => 1},
{"Ja" => 0, "Nee" => 0, => "Bijna" => 0, "nil" => 5}, 
{"Ja" => 0, "Nee" => 1, => "Bijna" => 3, "nil" => 1}, 
{"Ja" => 0, "Nee" => 1, => "Bijna" => 3, "nil" => 1},
{"Ja" => 3, "Nee" => 2, => "Bijna" => 0, "nil" => 0}
}

Please note that each horizontal in the hash is the count of the vertical in the array.

Yielding a new array of arrays (of arrays) is also acceptable, although I like the hash better:

[
[["Ja", 2], ["Nee", 2], ["Bijna", 1], ["nil", 1]],
[[etc]]
]
4
  • 1
    Welcome to SO. Please read "How to Ask" and "minimal reproducible example", along with meta.stackoverflow.com/q/261592/128421. It looks like you're asking us to write code for you because you don't show us what you tried and what's wrong with it. It's better for us to see your code so we can either fix it or show you where you went wrong. Commented Dec 2, 2016 at 21:21
  • Please down vote this one as well then: stackoverflow.com/questions/569694/… ;-). I didn't add my code because it was boring and won't add anything to the question. Any one who spend more than 1 day with Ruby will know the meaning of .map, .select, .flatten, etc and how it relates to the question. That said, I will take your comment into account moving forward. Thank you as well for the edits to the question. Commented Dec 2, 2016 at 21:26
  • Existing questions, especially legacy questions and especially ones almost 8 years old, show similar and worse problems but that doesn't reduce the need to meet the current goals and guidelines of the site. The site evolves and we try to keep up with new incoming questions and fix old ones. It's expected you'll try to follow the guidelines in place when you ask, not look for justification in the past. Commented Dec 2, 2016 at 21:32
  • Fair enough, that makes sense. I would appreciate some help though, regarding my question. Can you help me figure this out? Commented Dec 2, 2016 at 21:36

3 Answers 3

2

Let a be your big array.

values = a.flatten.uniq
all_values_hash = Hash[values.zip([0] * values.count)]
a.transpose.map do |arr| 
  arr.each_with_object(Hash.new(0)) { |item, hash| hash[item] += 1 }          
end.map { |h| all_values_hash.merge(h) }
Sign up to request clarification or add additional context in comments.

3 Comments

I like the idea of merging each constructed hash with all_values_hash.
Thank you. Just left the office. Will try your suggestion over the weekend.
Went with Cary's approach but thank you for taking the time to help me.
1
arr = [
  ["Ja",    nil,  "Bijna",    nil,  "Ja"],
  ["Nee",   nil,    "Nee",   "Ja", "Nee"],
  [nil,     nil,  "Bijna",  "Nee", "Nee"],
  ["Ja",    nil,      nil,  "Nee",  "Ja"],
  ["Bijna", nil,  "Bijna",  "Nee",  "Ja"]
]

keys = arr.flatten.uniq
  #=> ["Ja", nil, "Bijna", "Nee"] 
arr.transpose.map { |col| col.each_with_object(keys.product([0]).to_h) { |e,h|
  h[e] += 1 } }
  #=> [{"Ja"=>2, nil=>1, "Bijna"=>1, "Nee"=>1},
  #    {"Ja"=>0, nil=>5, "Bijna"=>0, "Nee"=>0},
  #    {"Ja"=>0, nil=>1, "Bijna"=>3, "Nee"=>1},
  #    {"Ja"=>1, nil=>1, "Bijna"=>0, "Nee"=>3},
  #    {"Ja"=>3, nil=>0, "Bijna"=>0, "Nee"=>2}] 

Note:

arr.transpose
  #=> [["Ja",    "Nee",     nil,  "Ja", "Bijna"],
  #    [nil,       nil,     nil,   nil,     nil],
  #    ["Bijna", "Nee", "Bijna",   nil, "Bijna"],
  #    [nil,      "Ja",   "Nee", "Nee",   "Nee"],
  #    ["Ja",    "Nee",   "Nee",  "Ja",    "Ja"]] 

1 Comment

Thank you. Just left the office. Will try your suggestion over the weekend.
1

Similar to the other solutions but logic reversed. I find it easier to read.

keys = my_array.flatten.uniq

final_result = my_array.transpose.map do |array|
 keys.each_with_object(Hash.new) do |key,result|
    result[key] = array.count(key)
 end
end

1 Comment

Went with Cary's approach but thank you for taking the time to help me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.