Добрый день! У меня возникла задача: необходимо "вытащить" из текста список слов, и вывести их, предварительно отсортировав по частоте вхождения (если несколько слов имеют одинаковую частоту, то они должны быть отсортированы по алфавиту). Вот с последней частью у меня и возникла проблема. На первый взгляд, ничего сложного в этом нет, берем слова, записываем их хеш, где в качестве ключа используется слово, а в качестве значения частота его вхождения и пишем в стиле a-la PERL что-то вроде
| Код | # пример входных данных DATA = { 'hello' => 20, 'foo' => 2, 'world' => 10, 'and' => 25, 'you' => 5, 'or' => 25, 'how' => 10, 'are' => 5, }
DATA.sort { |a, b| -(a[1] <=> b[1]) || (a[0] <=> b[0]) }.each { |pair| printf "%03d: %s\n", pair[1], pair[0] }
|
и получаем... правильно, не совсем то, что нужно. Выведенные данные действительно отсортированы по частоте вхождения, но вот с алфавитом имеются определённые проблемы. Сижу, разбираюсь и прихожу к выводу, что 0 есть истина (о чём, кстати, в "Programming Ruby" честно написано - "Any value that is not nil or the constant false is true")! Хорошо, тогда на мне ум приходит другая "гениальная" мысль - а давайте-ка использовать побитовое ИЛИ, что гарантировано даст возможность вычисления всех "сравнений". Да, но ведь в этом случае мы можем получитьвыражение 1 | -1, которое даст совсем не тот результат, который нужен. Следовательно, этот вариант тоже не подходит. В результате я пришел в селдующему варианту:
| Код | class Array def compare_result self.find { |condition| not condition.zero? } || 0 end end
DATA.sort { |a, b| [-(a[1] <=> b[1]), a[0] <=> b[0]].compare_result }.each { |pair| printf "%03d: %s\n", pair[1], pair[0] }
|
Ну и, наконец, озвучу свой вопрос - а не дурак ли я нет ли более простого варианта для решения задачи сортировки по нескольким условиям сразу? Меня не оставляет мысль, что это должно решаться как-то проще... |