Объединить несколько массивов - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть массив массивов, как показано ниже.

[
  ["Horse", 8, 0, 0, 0],
  ["Horse", 0, 0, 12, 0],
  ["Horse", 0, 7, 0, 0],
  ["Dog", 1, 0, 0, 0],
  ["Dog", 0, 0, 3, 0],
  ["Dog", 0, 3, 0, 0],
  ["Test", 5, 0, 0, 0],
  ["Test", 0, 0, 2, 0],
  ["Test", 0, 0, 0, 2],
  ["Cat", 5, 0, 0, 0],
  ["Cat", 0, 0, 4, 0],
  ["Cat", 0, 2, 0, 0]
]

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

[
  ["Horse", 8, 7, 12, 0],
  ["Dog", 1, 3, 3, 0],
  ["Test", 5, 0, 2, 2],
  ["Cat", 5, 2, 4, 0]
]

Пока у меня есть эта функция:

array.each_with_index do |line, idx|
  if array[idx+1].present? && line[0] == array[idx+1][0]
    line.each_with_index do |l, i|
      if l != 0 && array[idx+1][i] == 0
        array[idx+1][i] = array[idx][i]
      end
    end
  end
end

Но это не совсем то, что я пытаюсь сделать, но яЯ близокУ кого-нибудь есть идеи?

Ответы [ 5 ]

0 голосов
/ 21 ноября 2018
arr = [["Horse", 8, 0, 0, 0], ["Horse", 0, 0, 12, 0], ["Horse", 0, 7, 0, 0],
       ["Dog",   1, 0, 0, 0], ["Dog",   0, 0,  3, 0], ["Dog",   0, 3, 0, 0],
       ["Test",  5, 0, 0, 0], ["Test",  0, 0,  2, 0], ["Test",  0, 0, 0, 2],
       ["Cat",   5, 0, 0, 0], ["Cat",   0, 0,  4, 0], ["Cat",   0, 2, 0, 0]]

require 'matrix'

arr.each_with_object({}) do |(k,*arr),h|
  h[k] = h.key?(k) ? (h[k] + Vector[*arr]) : Vector[*arr]
end.map { |a,v| [a, *v.to_a] }
  #=> [["Horse", 8, 7, 12, 0],
  #    ["Dog",   1, 3,  3, 0],
  #    ["Test",  5, 0,  2, 2],
  #    ["Cat",   5, 2,  4, 0]]

Требуется 'matrix' загружает класс Vector , а также Matrix .См. Vector :: [] , Vector # + и Vector # to_a .

Для этого не требуется, чтобы элементы arr былизаказан любым способом.

0 голосов
/ 21 ноября 2018

Следующий простой,

hash = array.group_by(&:first)
hash.map { |k,v| v.map { |x| x[1..-1] }.transpose.map {|x| x.reduce(:+)}.unshift(k) }
0 голосов
/ 21 ноября 2018

Не уверен, что вопрос, но предполагая, что данный массив равен arr, вы можете получить результат:

arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map{|a| a.inject(:+)}]}

или, как указал Кэри Свовеланд:

arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map(&:sum)]}

Результат:

[
  ["Horse", 8, 7, 12, 0],
  ["Dog", 1, 3, 3, 0],
  ["Test", 5, 0, 2, 2],
  ["Cat", 5, 2, 4, 0]
]
0 голосов
/ 21 ноября 2018

с этим у вас не будет ограничения после имени животного ["Dog", 1, 4, 5, 0, 6, 3, ...]

array.group_by { |obj| obj[0] }.map do |key, values| 
  rest = values.reduce([]) do |memo, value|
    value[1..-1].each_with_index do |item, i|
      memo[i] ||= 0
      memo[i] = [item, memo[i]].max
    end
    memo
  end
  [key] + rest
end
0 голосов
/ 21 ноября 2018

Если исходный массив массивов хранится в arr:

arr.each_with_object(Hash.new { |h, k| h[k] = [0] * 4 }) do |(name, *vals), acc|
  (0...vals.size).each { |i| acc[name][i] += vals[i] }
end.map { |k, v| [k, *v] }
#⇒ [["Horse", 8, 7, 12, 0],
#   ["Dog", 1, 3, 3, 0],
#   ["Test", 5, 0, 2, 2],
#   ["Cat", 5, 2, 4, 0]]

Ключом к решению является сохранение хеша и его преобразование в массив в самом конце.Хеш проще искать и работать в целом.

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

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