Рубин, объединяющий предметы в массивах? - PullRequest
1 голос
/ 10 апреля 2011

У меня есть метод, который выводит различное количество массивов, например, так:

[["unidentified object", 50], ["person", 22], ["car", 55], ["SUV", 32], ["large_vehicle", 76]] 
[["unidentified object", 167], ["person", 104], ["car", 265], ["SUV", 129], ["large_vehicle", 355]] 
[["unidentified object", 1963], ["person", 413], ["car", 1962], ["SUV", 996], ["large_vehicle", 2027]] 
[["unidentified object", 1526], ["person", 373], ["car", 1560], ["SUV", 765], ["large_vehicle", 1706]] 
[["unidentified object", 1234], ["person", 316], ["car", 1705], ["SUV", 895], ["large_vehicle", 1712]]

Однако мне бы очень хотелось иметь хэш, в котором итоги каждого элемента суммируются по всем массивамкак:

[{:class => "unidentified object", :count => 7234}, {:class => "person", :count => 5231}, {...}]

Имеет ли это смысл?Мне совершенно необходимо прочитать о том, как работают массивы и методы хэширования, но любые советы действительно помогут.

Ответы [ 7 ]

5 голосов
/ 10 апреля 2011

Это должно сработать:

data = [
  [["unidentified object", 50], ["person", 22], # ...
  # ...
]

pairs = data.flatten(1)
grouped_by_class = pairs.group_by(&:first)
output = grouped_by_class.map do |cls, list| 
  {:class => cls, :count => list.map(&:last).inject(&:+)}
end

Если у вас нет веской причины для того, чтобы вывод был точно таким, как вы его описали, я предлагаю пойти по чему-то более простому, например {'unidentified object' => 7234, ...}, вы можетечто как вывод с этим кодом:

data.flatten(1).inject(Hash.new(0)) do |h, (cls, count)|
  h[cls] += count
  h
end
4 голосов
/ 10 апреля 2011

Введите ваши данные в виде массива массивов массивов:

a = [
    [["unidentified object", 50], ["person", 22], ["car", 55], ["SUV", 32], ["large_vehicle", 76]],
    [["unidentified object", 167], ["person", 104], ["car", 265], ["SUV", 129], ["large_vehicle", 355]],
    [["unidentified object", 1963], ["person", 413], ["car", 1962], ["SUV", 996], ["large_vehicle", 2027]],
    [["unidentified object", 1526], ["person", 373], ["car", 1560], ["SUV", 765], ["large_vehicle", 1706]],
    [["unidentified object", 1234], ["person", 316], ["car", 1705], ["SUV", 895], ["large_vehicle", 1712]],
]

Вы можете сделать один вкладыш:

x = a.flatten(1).inject(Hash.new(0)) { |h, p| h[p[0]] += p[1]; h }.map { |k, v| { :class => k, :count => v } }
1 голос
/ 10 апреля 2011
data = [
    [["unidentified object", 50], ["person", 22], ["car", 55], ["SUV", 32], ["large_vehicle", 76]],
    [["unidentified object", 167], ["person", 104], ["car", 265], ["SUV", 129], ["large_vehicle", 355]],
    [["unidentified object", 1963], ["person", 413], ["car", 1962], ["SUV", 996], ["large_vehicle", 2027]],
    [["unidentified object", 1526], ["person", 373], ["car", 1560], ["SUV", 765], ["large_vehicle", 1706]],
    [["unidentified object", 1234], ["person", 316], ["car", 1705], ["SUV", 895], ["large_vehicle", 1712]],
]

Вы можете довольно легко вернуть такой тип хэша, который выглядит немного более гибким, чем массив хэшей:

data.flatten(1).inject({}){|h, a| h[a[0]] ||= 0; h[a[0]]+=a[1]; h}
#=> {"person"=>1228, "unidentified object"=>4940, "SUV"=>2817, "car"=>5547, "large_vehicle"=>5876}

Или, для вашей точной цели:

data.flatten(1).inject({}){|h, a| h[a[0]] ||= 0; h[a[0]]+=a[1]; h}.map{|k,v| {:class => k, :count => v}}
#=> [{:class=>"person", :count=>1228}, {:class=>"unidentified object", :count=>4940}, {:class=>"SUV", :count=>2817}, {:class=>"car", :count=>5547}, {:class=>"large_vehicle", :count=>5876}]
1 голос
/ 10 апреля 2011

Вот простое инкрементное решение, которое будет работать в любой разумной версии Ruby ...

@r = Hash.new 0
def merge a
  a.each { |(c, n)| @r[c] += n }
end

merge [["unidentified object", 50], ["person", 22], ["car", 55], ["SUV", 32], ["large_vehicle", 76]] 
merge [["unidentified object", 167], ["person", 104], ["car", 265], ["SUV", 129], ["large_vehicle", 355]] 
merge [["unidentified object", 1963], ["person", 413], ["car", 1962], ["SUV", 996], ["large_vehicle", 2027]] 
merge [["unidentified object", 1526], ["person", 373], ["car", 1560], ["SUV", 765], ["large_vehicle", 1706]] 
merge [["unidentified object", 1234], ["person", 316], ["car", 1705], ["SUV", 895], ["large_vehicle", 1712]]

p @r.map { |k, v| {:class => k, :count => v}}
1 голос
/ 10 апреля 2011
a = [[["unidentified object", 50], ["person", 22], ["car", 55], ["SUV", 32], ["large_vehicle", 76]],
[["unidentified object", 167], ["person", 104], ["car", 265], ["SUV", 129], ["large_vehicle", 355]], 
[["unidentified object", 1963], ["person", 413], ["car", 1962], ["SUV", 996], ["large_vehicle", 2027]], 
[["unidentified object", 1526], ["person", 373], ["car", 1560], ["SUV", 765], ["large_vehicle", 1706]],
[["unidentified object", 1234], ["person", 316], ["car", 1705], ["SUV", 895], ["large_vehicle", 1712]]]

В ruby1.9 следующее hash даст вам более естественную форму, чем та, о которой вы просили, и используется как промежуточная форма для получения array, которая является вашей желаемой формой.

hash = a.flatten(1).each_with_object(Hash.new(0)){|(k, v), h| h[k] += v}
array = hash.each_with_object([]){|(k, v), h| h.push({class: k, count: v})}

Вот способ сделать это напрямую

a.flatten(1).group_by{|k, v| k}.map{|k, v| {class: k, count: v.inject(0){|n, (k, v)| n += v}}}
1 голос
/ 10 апреля 2011

Предполагая, что ваши выходные массивы сами по себе являются итеративными, вы можете сделать это:

result = {}

arrays.each do |arr|
  if result[arr[0]]
    result[arr[0]] += arr[1]
  else
    result[arr[0]] = arr[1]
  end
end 

Это будет выполнять итерацию по выходным массивам и предполагать, что первый элемент каждого подмассива может быть обработанв качестве хеш-ключа он суммирует значения для каждого ключа, если ключ существует в хеш-результатах.Если ключ не существует в хэше, он просто добавляется в хэш результатов.

Надеюсь, что это поможет.

1 голос
/ 10 апреля 2011

Будет ли это работать?

result = Hash.new
array.each do |pair|

  result[pair.first] = 0 unless result.has_key? pair.first
  result[pair.first]+= pair.last
end

Не совсем вывод, который вы хотели, но что-то вроде этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...