Реализовать метод слияния в ruby - PullRequest
0 голосов
/ 18 октября 2019

Я пытаюсь реализовать метод слияния в моем коде.

A = { "a" => 200, "b" => 100 }
B = { "b" => 100, "c" => 300 }

Поэтому, когда я вызываю A.merge_method(B) в моей основной функции, она должна вернуть

A.merge_method(B) #=> {"a"=>200, "b"=>200, "c"=>300}

Как я могу реализовать без использования метода слияния?

Ответы [ 2 ]

4 голосов
/ 18 октября 2019

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

module HashWithMergeReduce
  refine Hash do
    def merge_reduce(*others, &op)
      hashes = [self, *others]
      hash_keys = hashes.map(&:keys).inject(Set.new, &:+)
      hash_keys.each do |key|
        hashes_with_key = hashes.select { |hash| hash.has_key?(key) }
        self[key] = hashes_with_key.map { |hash| hash[key] }.reduce(&op)
      end
      self
    end
  end
end

module TestHashWithMergeReduce
  using HashWithMergeReduce
  a = { "a" => 200, "b" => 100 }
  b = { "b" => 100, "c" => 300 }  
  puts a.merge_reduce(b, &:+)
  # => {"a"=>200, "b"=>200, "c"=>300}
end
2 голосов
/ 18 октября 2019

Я не могу заставить себя добавить метод merge_method в класс Hash, не только потому, что он загрязняет основной класс, но и потому, что он применим только к небольшому подмножеству хэшей, для которых все значенияявляются числовыми

Можно refine Hash, как это сделал @Amadan, но я думаю, что имеет больше смысла просто создать метод, похожий на методы модуля, которые ведут себя как функции (например, Math::sqrt), чтопринимает все хэши в качестве аргументов.

def sum_values_by_key(*hashes)
  hashes.each_with_object(Hash.new(0)) { |g,h| g.each { |k,v| h[k] += v } }
end

sum_values_by_key({ "a" => 200, "b" => 100 }, { "b" => 100, "c" => 300 })
  #=> {"a"=>200, "b"=>200, "c"=>300}

sum_values_by_key({ "a" => 200, "b" => 100 }, { "b" => 100, "c" => 300 },
                  { "a" => 150, "c" => 250 }) 
  #=> {"a"=>350, "b"=>200, "c"=>550}

Используется форма Hash :: new , которая определяет значение по умолчанию, которое здесь равно нулю. Выражение:

h[k] += v

расширяется до:

h[k] = h[k] + v

Если этот хэш был определен h = Hash.new(0) и h имеет ключ k, h[k] справаравенства вычисляется для возврата значения k. Однако, если h не имеет ключа k, h[k] справа возвращает значение по умолчанию, ноль, чтобы стать:

h[k] = 0 + v

Я также изменил имя метода насделать его более значимым.

...