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

#ruby

#ruby

Вопрос:

Имея два массива разного размера, я хотел бы получить longer массив в виде ключей, а shorter один — в виде значений. Однако я не хочу, чтобы какие-либо ключи оставались пустыми, поэтому мне нужно продолжать выполнять итерации по shorter массиву, пока все ключи не получат значение.

РЕДАКТИРОВАТЬ: я хочу, чтобы массив дольше оставался нетронутым, но без пустых значений, это означает, что продолжайте выполнять итерации по более коротким, пока все ключи не получат значение.

 longer  = [1, 2, 3, 4, 5, 6, 7]
shorter = ['a', 'b', 'c']

Hash[longer.zip(shorter)]
#=> {1=>"a", 2=>"b", 3=>"c", 4=>nil, 5=>nil, 6=>nil, 7=>nil}
  

Ожидаемый результат

 #=> {1=>"a", 2=>"b", 3=>"c", 4=>"a", 5=>"b", 6=>"c", 7=>"a"}
  

Комментарии:

1. Опубликуйте ожидаемый результат.

2. longer.each_with_object({}).with_index { |(x,hsh),i| hsh[x] = shorter[i % shorter.size] } #=> {1=>"a", 2=>"b", 3=>"c", 4=>"a", 5=>"b", 6=>"c", 7=>"a"}

Ответ №1:

Вот элегантный вариант. Вы можете «зациклить» короткий массив

 longer  = [1, 2, 3, 4, 5, 6, 7]
shorter = ['a', 'b', 'c']

longer.zip(shorter.cycle).to_h # => {1=>"a", 2=>"b", 3=>"c", 4=>"a", 5=>"b", 6=>"c", 7=>"a"}
  

Комментарии:

1. @AndreyDeineko: много переполнения стека 🙂

2. Аккуратно!! Вообще не знал о цикле : O

3. Я вижу все эти ответы и понимаю, что я бы тоже начал думать о некоторых each_with_object / inject вещах.. я учусь, учусь и еще раз учусь

4. @AndreyDeineko: each_with_object это мой инструмент для перехода. это швейцарский армейский нож перечислимой обработки 🙂

5. @CarySwoveland: о, прекрати это, ты 🙂

Ответ №2:

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

 mapped = longer.each_slice(shorter.length).to_a.map do |slice|
           Hash[slice.zip(shorter)]
         end
=> [{1=>"a", 2=>"b", 3=>"c"}, {4=>"a", 5=>"b", 6=>"c"}, {7=>"a"}]
  

Объедините все хэши внутри отображенного массива в один хэш

 final = mapped.reduce Hash.new, :merge
=> {1=>"a", 2=>"b", 3=>"c", 4=>"a", 5=>"b", 6=>"c", 7=>"a"}
  

Комментарии:

1. Что ж, я просто оставлю это здесь для альтернативного (более длительного) подхода. Ответ Серджио — лучший способ добиться этого.

2. По крайней мере, вы были первым, кто понял намерения операционной системы.

3. @sagarpandya82 😉 Спасибо, что заметили, что

Ответ №3:

Вот забавный ответ.

 longer  = [1, 2, 3, 4, 5, 6, 7]
shorter = ['a', 'b', 'c']

h = Hash.new do |h,k|
  idx = longer.index(k)
  idx ? shorter[idx % shorter.size] : nil
end
  #=> {}

h[1] #=> a
h[2] #=> b
h[3] #=> c
h[4] #=> a
h[5] #=> b
h[6] #=> c
h[7] #=> a
h[8] #=> nil

h #=> {}

h.values_at(3,5) #=> ["c", "b"] 
  

Если этого недостаточно (например, если вы хотите использовать Hash такие методы, как keys , key? , merge , to_a и т.д.), вы могли бы довольно легко создать связанный хэш:

 longer.each { |n| h[n] = h[n] }
h #=> {1=>"a", 2=>"b", 3=>"c", 4=>"a", 5=>"b", 6=>"c", 7=>"a"}