2014-10-11 5 views
4

Может ли кто-нибудь показать мне, как сортировать вложенный массив на основе пользовательских строк? Например, есть способ сортировки:Сортировка массива с использованием пользовательских настроек сортировки?

[['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

по "Orange", "Yellow", а затем "Blue"? Конечный результат будет выглядеть так:

[['Green','Orange'],['Purple','Yellow'],['Red','Blue']] 

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

+1

Добро пожаловать на SO. Хороший письменный вопрос. Очень кратки. –

ответ

3

Это задача для group_by и values_at:

ORDER = %w[Orange Yellow Blue] 
ary = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

ary.group_by{ |a| a.last }.values_at(*ORDER) 
# => [[["Green", "Orange"]], [["Purple", "Yellow"]], [["Red", "Blue"]]] 

Вот что group_by приносит партии:

ary.group_by{ |a| a.last } 
# => {"Blue"=>[["Red", "Blue"]], 
#  "Orange"=>[["Green", "Orange"]], 
#  "Yellow"=>[["Purple", "Yellow"]]} 

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

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

Если вы хотите точно такой же массив из-массивов, как в вашем примере, flatten результат сразу:

ary.group_by{ |a| a.last }.values_at(*ORDER).flatten(1) 
# => [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 

Вы не хотите делать, если там будет несколько «Orange» , «Желтый» или «Синий», поскольку результат не будет очень полезен.

+0

Спасибо за это! Отлично! – LewlSauce

2

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

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

strs = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 

ordering = %w(Orange Yellow Blue) 

p strs.sort { |a,b| ordering.index(a[1]) <=> ordering.index(b[1]) } 

# [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 
+0

Спасибо тонну. Это также сработало. :) Очень признателен! – LewlSauce

7

sort_by всегда очень удобно для такого рода сортировки:

a = [['Red','Blue'],['Green','Orange'],['Purple','Yellow']] 
order_array = ['Orange', 'Yellow', 'Blue'] 

p a.sort_by { |arr| order_array.index(arr[1]) } 

# => [["Green", "Orange"], ["Purple", "Yellow"], ["Red", "Blue"]] 
+0

Спасибо за помощь! Работал и для меня! – LewlSauce

0

Вот такой подход, который позволяет «Апельсин», «Желтый» и «Blue», чтобы быть в любом месте в каждом массиве, и каждый массив может содержать не все, некоторые или все эти три цвета. Каждый массив, а также содержащий массив сортируются, используя заданный порядок строк. Нормальная сортировка массива применяется, так что, если первый элемент каждого из двух массивов одинаковы, вторые элементы сравниваются, и т.д.

я временно переопределить String#<=>, то вроде обычным способом, а затем восстановить String#<=> перед возвращением.

Код

def reorder(arr) 
    String.send(:alias_method, :old_compare, :<=>) 
    String.class_eval do 
    define_method(:<=>) do |other| 
     order = ["Blue", "Yellow", "Orange"] # increasing priority 
     self_ndx = order.index(self) || -1 
     other_ndx = order.index(other) || -1 
     other_ndx <=> self_ndx 
    end 
    end 
    a = arr.map(&:sort).sort 
    String.send(:alias_method, :<=>, :old_compare) 
    String.send(:undef_method, :old_compare) 
    a 
end 

Примеры

reorder [["Red", "Blue"], ["Green", "Orange"], ["Purple", "Yellow"]] 
    #=> [["Orange", "Green"], ["Yellow", "Purple"], ["Blue", "Red"]] 
reorder [["Blue", "Orange"], ["Purple", "Green"], ["Purple", "Orange"]] 
    #=> [["Orange", "Blue"], ["Orange", "Purple"], ["Purple", "Green"]] 
reorder [["Yellow", "Orange"], ["Orange", "Orange"], ["Blue", "Yellow"]] 
    #=> [["Orange", "Orange"], ["Orange", "Yellow"], ["Yellow", "Blue"]] 
reorder [["Yellow", "Purple"], ["Purple", "Orange", "Blue"], ["Blue", "Yellow"]] 
    #=> [["Orange", "Blue", "Purple"], ["Yellow", "Blue"], ["Yellow", "Purple"]] 
Смежные вопросы