ruby сопоставляет функцию с несколькими массивами

#arrays #ruby #loops #iteration #idioms

#массивы #ruby #циклы #итерация #идиомы

Вопрос:

У меня есть 2 массива

    asc = [0, 1, 2, 3, 4, 5]
   dsc = [5, 4, 3, 2, 1, 0]
 

Мне нужен новый массив, который является результатом умножения каждого соответствующего элемента в asc и dsc

Я привык к Clojure, где я бы просто map

 (map #(* %1 %2) asc dsc) ;=> (0 4 6 6 4 0)
 

Является ли их эквивалентом в Ruby, каким был бы идиоматический способ сделать это в Ruby?

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

Я просто пишу:

 i = 0
res = []

while i < asc.length() do
  res.append(asc[i] * dsc[i])
end
 

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

1. Вы забыли запятые в asc и dsc .

Ответ №1:

Используйте zip, чтобы объединить каждый элемент с соответствующим ему массивом из двух элементов, а затем сопоставить

 asc.zip(dsc).map { |a, b| a * b }
 => [0, 4, 6, 6, 4, 0] 
 

Ответ №2:

Похоже, что dsc («по убыванию») является производным от asc («по возрастанию»), и в этом случае вы могли бы написать:

 asc.each_index.map { |i| asc[i] * asc[-i-1] } 
  #=> [0, 4, 6, 6, 4, 0]
 

Вы также можете написать:

 [asc, dsc].transpose.map { |a,d| a*d }
  #=> [0, 4, 6, 6, 4, 0]
 

или:

 require 'matrix'

Matrix[asc].hadamard_product(Matrix[dsc]).to_a.first
  #=> [0, 4, 6, 6, 4, 0]
 

См. Matrix#hadamard_product .

Ответ №3:

Используйте map и with_index :

 asc = [0, 1, 2, 3, 4, 5]
dsc = [5, 4, 3, 2, 1, 0]
res = asc.map.with_index{ |el, i| el * dsc[i] }
puts res.inspect
# [0, 4, 6, 6, 4, 0]
 

В качестве альтернативы можно использовать each_index и map :

 res = asc.each_index.map{ |i| asc[i] * dsc[i] }
 

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

1. Я думаю zip , что это будет использоваться чаще, но у него есть недостаток, по сравнению с вашим ответом, в создании временного массива ( asc.zip(dsc) ). Вы могли бы вместо этого написать это asc.each_index.map { |i| asc[i] * dsc[i] } (хотя я не думаю, что это предпочтительнее).

2. @CarySwoveland Спасибо, что предложили другое решение! Я добавил это в свой ответ.

3. @CarySwoveland еще один способ избежать временного массива asc.enum_for(:zip, dsc)

Ответ №4:

Вы также можете написать, как показано ниже:

 asc = [0, 1, 2, 3, 4, 5]
dsc = [5, 4, 3, 2, 1, 0]

p asc.zip(dsc).collect{|z| z.inject(:*)}
[0, 4, 6, 6, 4, 0]