Более или менее тот же суп, что и в других ответах.
После прочтения файла a
содержит:
#=> ["ID : 001\n", "category : 2\n", "length : 18.33\n", "\n", "ID : 002\n", "category : 1\n", "length : 19.75\n", "\n", "ID : 003\n", "category : 1\n", "length : 18.8\n", "\n", "ID : 004\n", "category : 3\n", "length : 17.9\n", "\n", "ID : 005\n", "category : 3\n", "length : 16.9\n", "\n", "ID : 006\n", "category : 2\n", "length : 17.9\n", "\n", "ID : 007\n", "category : 3\n", "length : 21.5\n", "\n", "ID : 008\n", "category : 1\n", "length : 20.7\n", "\n", "ID : 009\n", "category : 1\n", "length : 16.5\n", "\n", "ID : 010\n", "category : 1\n", "length : 23\n", "\n", "ID : 011\n", "category : 2\n", "length : 18.73\n", "\n", "ID : 012\n", "category : 3\n", "length : 17.9\n", "\n", "ID : 013\n", "category : 3\n", "length : 23.4\n", "\n", "ID : 014\n", "category : 3\n", "length : 17.9\n", "\n", "ID : 015\n", "category : 3\n", "length : 20.93"]
Тогда вам нужно превратить этот беспорядок в более удобный объект, лучше всего использовать Array of Hashes, поэтому:
res = a.map{ |e| e.chomp.gsub(/\s+/, "").split(':') }.reject(&:empty?).each_slice(3).map(&:to_h)
#=> [{"ID"=>"001", "category"=>"2", "length"=>"18.33"}, {"ID"=>"002", "category"=>"1", "length"=>"19.75"}, {"ID"=>"003", "category"=>"1", "length"=>"18.8"}, ...
Может быть, лучше иметь значение length
в виде числа с плавающей запятой:
res.map { |h| h['length'] = h['length'].to_f }
Наконец, группировка по "category"
и преобразование значений результирующего хеша:
res.group_by { |h| h['category']}.transform_values { |v| [v.size, v.sum { |h| h['length'] }] }
#=> {"2"=>[3, 54.959999999999994], "1"=>[5, 98.75], "3"=>[7, 136.43]}
Один лайнер, просто для удовольствия:
a.map{ |e| e.chomp.gsub(/\s+/, "").split(':') }.reject(&:empty?).each_slice(3).map(&:to_h).tap { |res| res.map { |h| h['length'] = h['length'].to_f } }.group_by { |h| h['category']}.transform_values { |v| [v.size, v.sum { |h| h['length'] }] }