Создайте хеш из массива, где значения являются индексами элементов - PullRequest
0 голосов
/ 28 мая 2018

У меня есть массив, и я хочу создать хеш, ключами которого являются элементы массива, а значениями (массивом) являются индексы массива.Я хочу получить что-то вроде:

array = [1,3,4,5]
... # => {1=>0, 3=>1, 4=>2, 5=>3}

array = [1,3,4,5,6,6,6]
... # => {1=>0, 3=>1, 4=>2, 5=>3, 6=>[4,5,6]}

Этот код:

hash = Hash.new 0
array.each_with_index do |x, y|
  hash[x] = y
end

отлично работает, только если у меня нет дублирующих элементов.Когда у меня есть дубликаты элементов, это не так.

Есть идеи о том, как я могу получить что-то подобное?

Ответы [ 3 ]

0 голосов
/ 28 мая 2018

Я добавляю свои два цента:

array = [1,3,4,5,6,6,6,8,8,8,9,7,7,7]

hash = {}
array.map.with_index {|val, idx| [val, idx]}.group_by(&:first).map do |k, v|
  hash[k] = v[0][1] if v.size == 1
  hash[k] = v.map(&:last) if v.size > 1
end

p hash #=> {1=>0, 3=>1, 4=>2, 5=>3, 6=>[4, 5, 6], 8=>[7, 8, 9], 9=>10, 7=>[11, 12, 13]}

Сбой при дублированном элементе, конечно, не соседствует.

Это расширенная версия, шаг за шагом, чтобы показать, какэто работает.

Основная идея состоит в том, чтобы создать временный массив с парами значений и индекса, а затем работать с ним.

array = [1,3,4,5,6,6,6]

tmp_array = []
array.each_with_index do |val, idx|
  tmp_array << [val, idx]
end
p tmp_array #=> [[1, 0], [3, 1], [4, 2], [5, 3], [6, 4], [6, 5], [6, 6]]

tmp_hash = tmp_array.group_by { |e| e[0] }
p tmp_hash #=> {1=>[[1, 0]], 3=>[[3, 1]], 4=>[[4, 2]], 5=>[[5, 3]], 6=>[[6, 4], [6, 5], [6, 6]]}

hash = {}
tmp_hash.map do |k, v|
  hash[k] = v[0][0] if v.size == 1
  hash[k] = v.map {|e| e[1]} if v.size > 1
end

p hash #=> {1=>1, 3=>3, 4=>4, 5=>5, 6=>[4, 5, 6]}

Его можно записать одной строкой в ​​виде:

hash = {}
array.map.with_index.group_by(&:first).map { |k, v| v.size == 1 ? hash[k] = v[0][1] : hash[k] = v.map(&:last) }
p hash
0 голосов
/ 29 мая 2018

Если вы готовы принять

{ 1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4,5,6] }

в качестве возвращаемого значения, вы можете написать следующее.

array.each_with_index.group_by(&:first).transform_values { |v| v.map(&:last) }
  #=> {1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4, 5, 6]}

Первый шаг в этом расчете следующий:

array.each_with_index.group_by(&:first)
  #=> {1=>[[1, 0]], 3=>[[3, 1]], 4=>[[4, 2]], 5=>[[5, 3]], 6=>[[6, 4], [6, 5], [6, 6]]}

Это может помочь читателям следить за последующими вычислениями.

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

ЗдесьВот пара примеров, в которых явно желательно, чтобы все значения были массивами.Пусть:

h_orig = { 1=>0,   3=>1,   4=>2,   5=>3,   6=>[4,5,6] }
h_mod    { 1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4,5,6] }

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

h_mod.transform_values(&:count)
  #=> {1=>1, 3=>1, 4=>1, 5=>1, 6=>3}
h_orig.transform_values { |v| v.is_a?(Array) ? v.count : 1 }

Создайте хеш h, ключи которого являются уникальными элементами array и значения которого равны индексу первого экземпляра элемента в массиве.

h_mod.transform_values(&:min)
  #=> {1=>0, 3=>1, 4=>2, 5=>3, 6=>4}
h_orig.transform_values { |v| v.is_a?(Array) ? v.min : v }

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

h_orig.transform_values { |v| [*v].count }
h_orig.transform_values { |v| [*v].min }

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

0 голосов
/ 28 мая 2018

Вы можете изменить логику на особый случай, когда ключ уже существует, превратив его в массив и выдвинув новый индекс:

arr = %i{a a b a c}

result = arr.each.with_object({}).with_index do |(elem, memo), idx|
  memo[elem] = memo.key?(elem) ? [*memo[elem], idx] : idx
end

puts result
# => {:a=>[0, 1, 3], :b=>2, :c=>4}

Однако стоит упомянуть, что все, что вы 'Попытка сделать это может быть выполнена по-другому ... у нас нет контекста.Как правило, рекомендуется сохранять единообразные типы данных key-val, например, тот факт, что значения здесь могут быть числами или массивами, немного напоминает запах кода.

Также обратите внимание, что это не имеет смыслаиспользовать Hash.new(0) здесь, если вы не намеренно устанавливаете значение по умолчанию (что нет причин делать).Используйте {} вместо

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