2016-01-08 8 views
0

У меня возникли проблемы, объясняя, что я ищу, так я приведу пример, скажем, у меня есть этот массив:Сортировка элементов в цикле

[ 
    [1, 2], 
    [1, 3], 
    [1, 4], 
    [2, 3], 
    [2, 4], 
    [3, 4] 
] 

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

в результате:

[ 
    [1, 2], 
    [2, 3], 
    [3, 4], 
    [1, 3], 
    [2, 4], 
    [1, 4] 
] 

Еще лучше было бы, если он мог бы цикл через обе колонки, чтобы предотвратить два числа в строке, насколько это возможно, идеальное решение было бы отсортировать исходный массив как:

[ 
    [1, 2], 
    [3, 4], 
    [1, 3], 
    [2, 4], 
    [1, 4], 
    [2, 3] 
] 

Leading до максимального расстояния между повторяющимися числами для каждого внутреннего массива (оба колонок принимаются во внимание).

Надеюсь, что я предоставил достаточную информацию, и я буду очень признателен за любые рекомендации, я до сих пор не знаю, что ничто не искало.

+1

Я не понимаю, как ездить на велосипеде через обе колонки, поэтому не может написать решение для этого. –

+0

Имеет ли значение расстояние между соседними предметами, или это просто, что для них лучше быть другим? – sawa

+1

Велоспорт не обеспечивает и не увеличивает чередование. Например, '[1, 1, 1, 1, 2, 3, 4]' приведет к '[1, 2, 3, 4, 1, 1, 1]' (три 1 в конце), хотя вы может упорядочить числа без повторения: '[1, 2, 1, 3, 1, 4, 1]' – Stefan

ответ

0

Предполагая исходный массив сортируется по первому элементу:

arr = 
    [ 
    [1, 2], 
    [1, 3], 
    [1, 4], 
    [2, 3], 
    [2, 4], 
    [3, 4], 
    ] 

res = [] 
arr_dup = arr.dup 
remaining_values = arr_dup.map { |el| el[0] } 
current_value = remaining_values.first 
loop do 
    arr_dup.each_with_index do |el, index| 
    if el[0] >= current_value 
     res << el 
     current_value = remaining_values.select { |v| v > el[0] }.first || remaining_values.first 
     remaining_values.delete_at(remaining_values.index(current_value)) 
     arr_dup.delete_at(index) 
     break 
    end 
    end 
    break if remaining_values.empty? 
end 

p arr #=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] 
p res #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]] 

Несколько тестов:

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [20, 2]] => 
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [1, 4]] 

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [5, 2], [20, 2]] => 
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [5, 2], [1, 4]] 
1

вы могли бы попробовать это

def func ary 
    ret = [] 
    # group by first ones, and each sort by second ones 
    a = ary.group_by{|i| i[0]}.map{|_,i| i.sort_by{|j| j[1]}} 
    # add to ret 
    (0...a.map{|i| i.size}.max).map{ 
    a.map{|i| ret << i.shift} 
    } 
    ret.compact 
end 
a = [[1, 2],[1, 3],[1, 4],[2, 3],[2, 4],[3, 4]] 
p func(a) 
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]] 
2

Я только обратиться к первой части вашего вопроса, поскольку я не понимаю, что вы подразумеваете под «Еще лучше было бы, если бы он мог переходить через обе колонки к как можно больше предотвратите два числа подряд ... ». Предложение «как можно больше» особенно хлопотно, поскольку оно относится к неопределенному критерию.

Позвольте arr быть вашим массивом. Элементы сортируются в вашем примере, но если они не были, то первым шагом будет:

arr.sort! 

См Array#sort! и Array#<=> для объяснения того, как рубин сортирует массивы, элементы которых являются массивы.

Существует множество способов получения желаемого заказа.Вот один, который использует Enumerable#chunk:

arr.chunk(&:first).flat_map {|_,a| a.map.with_index {|i,b| [b,i]}}.sort.map(&:last) 
    #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]] 

меры заключаются в следующем:

e = arr.chunk(&:first) 
    #=> #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each> 

Мы можем увидеть элементы этого интервьюером, которые передаются в блок с помощью Enumerator#each (который вызывает Array#each), путем преобразования его в массив:

e.to_a 
    #=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]] 

Дальнейшего:

f = e.flat_map { |_,a| a.map.with_index { |i,b| [b,i] } } 
    #=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]], [0, [2, 3]], [1, [2, 4]], [0, [3, 4]]] 
g = f.sort 
    #=> [[0, 1, 2], [0, 2, 3], [0, 3, 4], [1, 1, 3], [1, 2, 4], [2, 1, 4]] 
g.map(&:last) 
    #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]] 

Давайте более внимательно посмотреть на расчет f:

h = e.flat_map 
    #=> #<Enumerator: #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each>:flat_map> 
h.to_a 
    #=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]] 

Вы можете думать о h как «соединение» переписчиком.

Первое значение h, [1, [[1, 2], [1, 3], [1, 4]]], передается в блок и захвачен блоками переменных с помощью параллельных (или кратного) назначения:

i, a = h.next 
    #=> [1, [[1, 2], [1, 3], [1, 4]]] 
i #=> 1 
a #=> [[1, 2], [1, 3], [1, 4]] 

В i не используются в вычисление блока, принято заменять эту переменную блока локальной переменной _.

Теперь мы можем выполнить расчет блока:

a.map.with_index { |i,b| [b,i] } 
    #=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]]] 

Остальные расчеты выполняются аналогично.

+1

Вместо того, чтобы строить массив с новыми элементами '[index, x, y]', я бы сохранил/вставлял оригинал элементов через '[index, [x, y]]', то есть 'arr.chunk (&: first) .flat_map {| _, a | a.map.with_index {| b, i | [i, b]}} .sort.map (&: last) '. – Stefan

+0

Хорошее предложение. Я редактировал, чтобы включить его. Благодарю. Читатели: еще один способ просмотра @ Комментарий Штефана заключается в том, что если, например, 'a = [[2, [1,3]], [1, [2,4]]],' a.sort.map (& : last) 'и' a.map (&: flatten) .sort.map {| b | b.last (2)} 'оба дают тот же результат:' [[2, 4], [1, 3]] '. Я действительно получил последнее в своем первоначальном ответе. –

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