2017-02-01 5 views
1

Я использую Ruby 2.4. Я хочу взять массив и добавить его элементы в массив массивов на основе их индекса. Так что, если я начинаю с массивомКак объединить два массива на основе индекса их элементов?

[1, 2, 3] 

, и я хочу, чтобы объединить, что с массивом

[4, 5, 6] 

я могу получить результат

[[1, 4], [2, 5], [3, 6]] 

С помощью этой функции

arr_of_arrays = arr_of_arrays.empty? ? arr : arr_of_arrays.zip(arr).map(&:flatten) 

Однако это ломается, если Я пытаюсь добавить элемент с большим количеством элементов, чем оригинал. Так что, если я пытаюсь добавить

[4, 5, 6, 7] 

для исходного массива, прямо сейчас я получаю

[[1, 4], [2, 5], [3, 6]] 

, но то, что я хочу

[[1, 4], [2, 5], [3, 6], [7]] 

Как настроить мой выше функции добиться этого?

ответ

1

Из документов:

Если размер любого аргумента меньше, чем размер исходного массива, ноль значения поставляются.

Поэтому вам не нужно беспокоиться о случае, когда второй массив короче.

Если первый массив короче, отложите его на nil на длину второго массива.

Вы можете использовать compact для удаления лишних nil s впоследствии.

Случай 1: a больше

a = [1, 2, 3, 4, 5] 
b = [6, 7, 8] 

a[b.count-1] ||= nil 
a.zip(b).map(&:flatten).map(&:compact) 

Результат:

[[1, 6], [2, 7], [3, 8], [4], [5]] 

Случай 2: b больше

a = [1, 2, 3] 
b = [4, 5, 6, 7, 8] 

a[b.count-1] ||= nil 
a.zip(b).map(&:flatten).map(&:compact) 

Результат:

[[1, 4], [2, 5], [3, 6], [7], [8]] 

Вариация с nil включена

a = [1, 2, 3, 4, 5] 
b = [6, 7, 8] 

a[b.count-1] ||= nil 
b[a.count-1] ||= nil 
a.zip(b).map(&:flatten)  # [[1, 6], [2, 7], [3, 8], [4, nil], [5, nil]]  

... и ...

a = [1, 2, 3] 
b = [4, 5, 6, 7, 8] 

a[b.count-1] ||= nil 
b[a.count-1] ||= nil 
a.zip(b).map(&:flatten)  # [[1, 4], [2, 5], [3, 6], [nil, 7], [nil, 8]] 

Примечание

  • Если a или b не должен быть изменен, вставить .clone где-клон их заранее.
  • .flatten был взят из примера OP; он выравнивает любые массивы, которые берут на себя роль целых чисел в примере. При необходимости оставить или оставить.
+0

Если бы я хотел, чтобы элемент «nil» появился в случае, когда один из массивов длиннее, как бы я сделал taht? Так, например, ваш случай 2 woudl приводит к [[1, 4], [2, 5], [3, 6], [7, nil], [8, nil]].Я понимаю, что это немного другой вопрос, поэтому, если вы хотите, чтобы я сделал другой пост, я могу сделать это. Спасибо –

+0

См. Edit ... – AnoE

+1

1. 'a' мутируется в случае 2. OP не сказал, если это было разрешено (в этом случае мы должны считать, что это no-no), но даже если все в порядке, a' не мутируется в случае 1. Эта непоследовательность является потенциальной проблемой. 2. 'map (&: flatten)' не имеет никакого эффекта, если, как в примере, элементы массивов сами по себе не массивы. Если, однако, это массивы, мы могли бы иметь a = [[[1,2], 3], 4]; b = [5,6]; c = a.zip (b) # => [[[[1, 2], 3], 5], [4, 6]], что и следовало ожидать, но 'c.map (&: flatten) # => [[1, 2, 3, 5], [4, 6]] ', который не является частью спецификации. –

0

Я хотел бы сделать ...

a << nil while a.length < b.length 
a.zip(b).map(&:compact) 

Это изменит ваш a массив, хотя, так что вы можете сделать операцию на dup а.

1

Похоже, вы хотите «безопасный» транспонирование. Это называется безопасным, потому что обычно tranpose вызывает ошибку, когда суб-массивы не имеют одинаковую длину:

def safe_transpose(*arrays) 
    l = arrays.map(&:length).max 
    arrays.map{|e| e.values_at(0...l)}.transpose.map(&:compact) 
end 

p safe_transpose([1, 2, 3, 4], [5, 6, 7]) 
#=> [[1, 5], [2, 6], [3, 7], [4]] 

p safe_transpose([1, 2, 3], [4, 5, 6], [7, 8, 9]) 
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 

Если вы хотите сохранить проложенный Nils, вы можете использовать:

def safe_transpose(*arrays) 
    l = arrays.map(&:length).max 
    arrays.map{|e| e.values_at(0...l)}.transpose 
end 

p safe_transpose([1, 2, 3, 4], [5, 6, 7]) 
#=> [[1, 5], [2, 6], [3, 7], [4, nil]] 

p safe_transpose([1, 2, 3], [4, 5, 6], [7, 8, 9]) 
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 

оригинальные массивы не изменяются.

0
a = [1,2,3] 
b = [4, 5, 6, 7] 
arr_of_arrays = [] 

я полагаю, вы можете легко проверить, что B.Size> a.size верно, так

b.each_with_index{|elem, index| a[index].nil? ? arr_of_arrays << [elem] : arr_of_arrays << [a[index],elem]} 

возвращает ожидаемый массив массивов:

=> [[1, 4], [2, 5], [3, 6], [7]] 
0
arr1 = [1, 2, 3] 
arr2 = [4, 5, 6, 7] 

def combine_two_arrays(arr1, arr2) 
    new_arr = (arr1.size > arr2.size) ? arr1.zip(arr2) : arr2.zip(arr1) 
    new_arr.map { |arr| arr.compact.sort } 
end 

combine_two_arrays(arr1, arr2) 
0
a = [1,2,3] 
b = [4,5,6,7] 

Array.new([a.size, b.size].max) { |i| [a[i],b[i]].compact } 
    #=> [[1, 4], [2, 5], [3, 6], [7]] 

Это не принимает ни один из элементов a или b соответствует nil.

Если вы хотите nil s включен, просто удалить .compact:

Array.new([a.size, b.size].max) { |i| [a[i],b[i]] } 
    #=> [[1, 4], [2, 5], [3, 6], [nil, 7]] 

В этом случае a и b разрешено иметь nil значения.

Смежные вопросы