2016-11-08 5 views
0

Я две строки, s1 и s2рубин sort_by несколько уровней сортировки

Я хочу, чтобы список символов (из обеих строк), отсортированных:

  • первый по тому, как много раз char появляется в одной из строк (большее значение)

eg "hello" и "goodbye" будет "lloogbehyd"

  • второй от того, появляются максимальные символы в S1 или S2

например, "hello" и "goodbye" бы "lloohegdby"

  • третий по алфавиту

например, "hello" и "goodbye" бы "lloohebdgy"

В настоящее время у меня есть этот код:

letters = (s1+s2).chars.uniq.sort_by{ |s| [s1.count(s), s2.count(s)].max }.reverse 

Сортирует от первого условия, как добавить другие уровни?

+0

Подсказка. Массивы сортируются по их первому элементу, а в случае галстука, их второго и так далее. – tadman

+0

Вы должны быть более точным при описании «секунды». Есть три возможности: большее число в 's1', равное число в' s1' и 's2' (в моем ответе и большее число в' s2'. Как их упорядочить в сортировке? (В моем ответе я предположил порядок, в котором я перечислял три возможности.) Просьба уточнить, редактируя, поскольку не каждый может заметить пояснительный комментарий. –

+0

@jtbandes, я так не думаю. Да, вопрос частично связан с многоуровневой сортировкой, но это также касается построение конкретных массивов, которые должны быть отсортированы. –

ответ

0

Использование String#count относительно неэффективно, так как вся строка перемещается для каждой уникальной буквы. Было бы более эффективным, за счет большего количества строк кода, создать счетный хэш, который можно сделать следующим образом (см. Hash::new).

s1 = "hello" 
s2 = "goodbye" 

h1 = s1.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 } 
    #=> {"h"=>1, "e"=>1, "l"=>2, "o"=>1} 
h2 = s2.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 } 
    #=> {"g"=>1, "o"=>2, "d"=>1, "b"=>1, "y"=>1, "e"=>1} 
hmx = (h1.keys | h2.keys).each_with_object({}) do |c,h| h[c] = 
    case h1[c] <=> h2[c] 
    when 1 then [-h1[c], -1] 
    when 0 then [-h1[c], 0] 
    else [-h2[c], 1] 
    end 
end 
    #=> {"h"=>[-1, -1], "e"=>[-1, 0], "l"=>[-2, -1], "o"=>[-2, 1], 
    # "g"=>[-1, 1], "d"=>[-1, 1], "b"=>[-1, 1], "y"=>[-1, 1]} 

Теперь мы можем сортировать с помощью Enumerable#sort_by

(s1+s2).each_char.sort_by { |c| [*hmx[c], c] }.join 
    #=> "lloooheebdgy" 

См Array#<=> (третий абзац) для объяснения того, как массивы сортируются.

Я сделал предположение о том, что если два символа привязывать для большинства случаев в одном из двух строк, каждый символ присваивается балл -1, 0 или 1. Персонаж с наименьшим счетом (если у них нет одинакового балла) предшествует другому персонажу в сортировке. А значению c присваивается оценка -1, если строка s1 содержит больше c, а не строку s1; оценка 0, если обе строки содержат одинаковое количество c; и оценка 1, если s2 содержит больше c, чем s1.

0

То, что я в конце концов сделал:

(s1+s2).chars.sort_by{ |s| 
    [-([s1.count(s), s2.count(s)].max), 
    s1.count(s) > s2.count(s) ? -1 : 1, 
    s] 
} 
#=> "lloohebdgy" 

Обобщенный ответ, что дает Array к sort_by блок позволяет определить уровни сортировки.

+0

Вы забыли '.join' после закрывающей скобки. Это возвращает' 'llooohbdeegy''. –

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