2016-06-28 3 views
2

Я пытаюсь получить массив Ruby массивов и группировать его, чтобы подсчитать его значения.Ruby Array группы массивов и подсчет значений

Массив имеет месяц, и логическое значение:

array = [["June", false], ["June", false], ["June", false], ["October", false]] 

Я хотел бы закончить новый массив, дайте мне знать, сколько ложно против истин в каждом месяце.

Пример: (где первый элемент в массиве месяц, второй отсчет ложной и третий является счетчиком истинно)

new_array = [["June", 3, 0]], ["October", 1, 0]] 

ответ

1

Использование Enumerable#group_by:

Array.group_by { |month, b| month }.map{ |month, xs| 
    [month, 
    xs.count {|_, b| !b}, # false 
    xs.count {|_, b| b}] # true 
} 
# => [["June", 3, 0], ["October", 1, 0]] 
+0

'Enumerable # group_by' возвращает хеш, а не массив. –

+0

@Jordan, Вот почему я приковал возвращаемое значение с помощью вызова 'map'. (и нужна дальнейшая обработка для подсчета 'true',' false's) – falsetru

+0

А, так вы и сделали. Виноват. –

-2
Array.group_by {|(Array, boolean)| Array }.map {|Array, match| [Array, match.count] } 
+2

Пробовали ли вы этот код, прежде чем отправил его? Вы знаете, что это не работает? –

+0

Он выдает следующую ошибку: формальный аргумент не может быть константой – perezdr

0

Я думаю, что это сделало бы хороший прецедент для операции reduce. Вы бы сделать что-то вроде:

arr = [["June", false], ["June", false], ["June", false], ["October", false]] 
logical_group = Hash.new{|h, k| h[k] = Hash.new(0) } 

arr.reduce(logical_group) do |red, ele| 
    red[ele.first][:false_count] += 1 unless ele.last 
    red[ele.first][:true_count] += 1 if ele.last 
    red 
end.reduce([]) do |red, (key, value)| 
    red << [key, value[:false_count], value[:true_count]] 
    red 
end 
0

Enumerable#group_by является полезным инструментом, но в данном случае это не самый лучший.

Если мы начинаем с хэша, значение которого по умолчанию равно [0, 0], мы можем сделать (почти) все - посмотреть месяц (или получить значение по умолчанию нового месяца) и добавить 1 к соответствующему индексу (0 для false и 1 для истинного) -в одном шаге:

array = [["June", false], ["June", false], ["June", false], ["October", false]] 

hsh = Hash.new {|h,k| h[k] = [0,0] } 
array.each {|mo, bool| hsh[mo][bool ? 1 : 0] += 1 } 

p hsh.map(&:flatten) 
# => [["June", 3, 0], ["October", 1, 0]] 
+0

Это тоже работает. Почему лучше, чтобы Enumerable # group_by? – perezdr

+0

С 'group_by' мы должны перебирать данные четыре раза: один раз, чтобы сделать группировку, один раз, чтобы подсчитать' true ', еще раз для' false', а затем снова, чтобы превратить Hash в массив. В приведенном выше примере нам нужно только повторить итерацию: один раз сделать подсчет и один раз превратить его в массив. –

+0

ОК, проверит его завтра с вашим ответом vs falsetru. – perezdr

0
array.map(&:dup) # we’ll mutate it 
    .group_by(&:shift) 
    .flat_map { |k, v| [k, v.partition { |e| e }.map(&:count)] } 
#⇒ [ ['June', [0, 3] ], ['October', [0, 1] ] ] 
Смежные вопросы