Следующие работы для любого количества школьных предметов и любого размера группировки (т. Е. Не только 2
).
Код
def count_groupings(arr, group_size)
combos = (arr.flat_map { |h| h.keys }.uniq - ["student"]).
repeated_combination(group_size).to_a.product([0]).to_h
arr.each do |h|
keys = h.keys.select { |k| h[k] == true }
combos.keys.each { |k| combos[k] += 1 if (k-keys).empty? }
end
combos
end
Примеры
arr = [
{"student"=>"1", "English"=>true, "Algebra"=>true, "History"=>false},
{"student"=>"2", "English"=>false, "Algebra"=>false, "History"=>true},
{"student"=>"3", "English"=>false, "Algebra"=>true, "History"=>false},
{"student"=>"4", "English"=>true, "Algebra"=>false, "History"=>true}
]
count_groupings(arr, 1)
#=> {["English"]=>2, ["Algebra"]=>2, ["History"]=>2}
count_groupings(arr, 2)
#=> {["English", "English"]=>2, ["English", "Algebra"]=>1, ["English", "History"]=>1,
# ["Algebra", "Algebra"]=>2, ["Algebra", "History"]=>0, ["History", "History"]=>2}
count_groupings(arr, 3)
#=> {["English", "English", "English"]=>2, ["English", "English", "Algebra"]=>1,
# ["English", "English", "History"]=>1, ["English", "Algebra", "Algebra"]=>1,
# ["English", "Algebra", "History"]=>0, ["English", "History", "History"]=>1,
# ["Algebra", "Algebra", "Algebra"]=>2, ["Algebra", "Algebra", "History"]=>0,
# ["Algebra", "History", "History"]=>0, ["History", "History", "History"]=>2}
Объяснение
См Array#repeated_combination.
Следующие шаги приведены для group_size #=> 2
.
a = arr.flat_map { |h| h.keys }
#=> ["student", "English", "Algebra", "History", "student", "English",
# "Algebra", "History", "student", "English", "Algebra", "History",
# "student", "English", "Algebra", "History"]
b = a.uniq
#=> ["student", "English", "Algebra", "History"]
c = b - ["student"]
#=> ["English", "Algebra", "History"]
d = c.repeated_combination(group_size)
#=> #<Enumerator: ["English", "Algebra", "History"]:repeated_combination(2)
e = d.to_a
#=> [["English", "English"], ["English", "Algebra"], ["English", "History"],
# ["Algebra", "Algebra"], ["Algebra", "History"], ["History", "History"]]
f = e.product([0])
#=> [[["English", "English"], 0], [["English", "Algebra"], 0],
# [["English", "History"], 0], [["Algebra", "Algebra"], 0],
# [["Algebra", "History"], 0], [["History", "History"], 0]]
combos = f.to_h
#=> {["English", "English"]=>0, ["English", "Algebra"]=>0, ["English", "History"]=>0,
# ["Algebra", "Algebra"]=>0, ["Algebra", "History"]=>0, ["History", "History"]=>0}
g = arr.each
#=> #<Enumerator: [{"student"=>"1", "English"=>true, "Algebra"=>true, "History"=>false},
# ...
h = g.next
#=> {"student"=>"1", "English"=>true, "Algebra"=>true, "History"=>false}
i = h.keys
#=> ["student", "English", "Algebra", "History"]
keys = i.select { |k| h[k] == true }
#=> ["English", "Algebra"]
j = combos.keys
#=> [["English", "English"], ["English", "Algebra"], ["English", "History"],
# ["Algebra", "Algebra"], ["Algebra", "History"], ["History", "History"]]
m = j.each
#=> #<Enumerator: [["English", "English"], ["English", "Algebra"],
# ...]:each>
k = m.next
#=> ["English", "English"]
(k-keys).empty?
#=> (["English", "English"] - ["English", "Algebra"]).empty?
#=> [].empty?
#=> true
combos[k] += 1
combos
#=> {["English", "English"]=>1, ["English", "Algebra"]=>0, ["English", "History"]=>0,
# ["Algebra", "Algebra"]=>0, ["Algebra", "History"]=>0, ["History", "History"]=>0}
k = m.next
#=> ["English", "Algebra"]
(k-keys).empty?
#=> (["English", "Algebra"] - ["English", "Algebra"]).empty?
#=> [].empty?
#=> true
combos[k] += 1
combos
#=> {["English", "English"]=>1, ["English", "Algebra"]=>1, ["English", "History"]=>0,
# ["Algebra", "Algebra"]=>0, ["Algebra", "History"]=>0, ["History", "History"]=>0}
Остальные расчеты аналогичны.При желании, можно написать
combos = (arr.flat_map { |h| h.keys }.uniq - ["student"]).
repeated_combination(group_size).map(&:uniq).product([0]).to_h
#=> {["English"]=>0, ["English", "Algebra"]=>0, ["English", "History"]=>0,
# ["Algebra"]=>0, ["Algebra", "History"]=>0, ["History"]=>0}
Обратите внимание на инициализацию combos
для group_size = 1
:
combos = (arr.flat_map { |h| h.keys }.uniq - ["student"]).
repeated_combination(group_size).to_a.product([0]).to_h
#=> {["English"]=>0, ["Algebra"]=>0, ["History"]=>0}
и для group_size = 3
combos = (arr.flat_map { |h| h.keys }.uniq - ["student"]).
repeated_combination(group_size).to_a.product([0]).to_h
#=> {["English", "English", "English"]=>0, ["English", "English", "Algebra"]=>0,
# ["English", "English", "History"]=>0, ["English", "Algebra", "Algebra"]=>0,
# ["English", "Algebra", "History"]=>0, ["English", "History", "History"]=>0,
# ["Algebra", "Algebra", "Algebra"]=>0, ["Algebra", "Algebra", "History"]=>0,
# ["Algebra", "History", "History"]=>0, ["History", "History", "History"]=>0}
альтернативной структуры данных
Если есть выбор структуры данных, хэш может быть проще работать, чем массив хэшей, и нет необходимости включать курсы, которые не участвуют в этом классе (особенно, когда учатся сотни курсов).
courses_by_student = {
1 => %w| English Algebra|,
2 => %w| History |,
3 => %w| Algebra |,
4 => %w| English History |
}
ли ваши хэши хранятся в массиве? –
Да! Они на самом деле читаются из csv как массив хэшей, где каждый хеш описывает конкретного ученика – zqe
Возможно, вы захотите обновить свой вопрос, чтобы отразить это :) –