Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [ 40 ] 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

4.14. Числовая сортировка массива 137

push(©РЕЗУЛЬТАТ, $ ) If КРИТЕРИЙ ($ ),

Функция Perl grep позволяет записать всю эту возню с циклами более компактно. В действительности функция grep спльио отличается от одноименной команды UNIX - она не имеет параметров для нумерации строк или инвертирования критерия и не ограничивается проверками регулярных выражений. Например, чтобы отфильтровать из массива очень большие числа или определить, с какими ключами хэша ассоциированы очень большие значения, применяется следующая запись:

gs = grep ( $ > 1 000 000 } @nums, ©pigs = grep { $users($ } > 1е7 } keys %users,

В следующем примере в ©matching заносятся строки, полученные от команды who и начинающиеся с gnat :

©matching = grep ( /"gnat / } who ,

Или другой пример:

©engineers = grep ( $ ->position() eq Engineer } ©employees.

Из массива ©employees извлекаются только те объекты, для которых метод positionO возвращает строку Engineer.

Grep позволяет выполнять и более сложные проверки:

@secondary as&istance = grep ( $ ->incorae >= 26 000 &&

$ ->income < 30 000 } ©applicants,

Однако в таких ситуациях бывает разумнее написать 1ии<л.

t> Смотри также-

Разделы «Рог Loops*, «РогеасЬ Loops* и «Loop Control* рег/.?г/«(1); описание функции grep вperlfunc{\); страница руководства г<"/го( 1) вашей системы (если есть); рецепт 4.12.

4.14. Числовая сортировка массива

Проблема

Требуется отсортировать cihicok чисел, однако функция Perl sort (по умолчанию) выполняет алфавитную сортировку в ASCII-порядке.

Решение

Воспользуйтесь функцией Perl sort с оператором числового сравнения, оператор <=>:

©Sorted = sort ( $а <=> $b } @Unsorted,



Комментарий

При вызове функции sort можно передавать необязательный программный блок, с помощью которого принятый по умолчанию алфавитный порядок сравнения заменяется вашим собственным. Функция сравнения вызывается каждый раз, когда sort сравнивает две величины. Сравниваемые значения загружаются в специальные пакетные переменные $а и $Ь, которые автоматически локализуются.

Функция сравнения должна возвращать отрицательное число, если значение $а должно находиться в выходных данных перед $Ь; О, если они совпадают или порядок несущественен; и положительное число, если значение $а должно находиться после $Ь. В Perl существуют два оператора с таким поведением; оператор <=> сортирует числа по возрастанию в числовом порядке, а стр сортирует строки но возрастанию в алфавитном порядке. По умолчанию sort использует сравнения в стиле стр.

Следующий фрагмент сортирует список идентификаторов процессов (PID) в массиве @pids, предлагает пользователю выбрать один PID и посылает сигнал TERM, за которым следует сигнал KILL. В необязательном программном блоке $а сравнивается с $Ь оператором <=>, что обеспечивает числовую сортировку.

# @pids - несортированный массив идентификаторов процессов foreach my $pid (sort { $a <=> $b } @pids) { print $pid\n ,

print Select a process ID to kill \n , chomp ($pid = <>),

die Exiting \n unless $pid U $pid =~ /"\d=$/, kill ( TERM ,$pid) sleep 2,

kill ( KILL ,$pid),

При использовании условия $a<=>$b или $a cmp $b список сортируется в порядке возрастания. Чтобы сортировка выполнялась в порядке убывания, достаточно поменять местами $а и $Ь в функции сравнения:

descending = sort { $b <=> $а } @unsorted,

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

Также возможна конструкция вида sort ИМЯ СПИСОК, где ИМЯ - имя функции сравнения, возвращающей -1, О или +1. В интересах быстродействия нормальные правила вызова не соблюдаются, а сравниваемые значения, как по волшебству, появляются в глобальных пакетных переменных $а и $Ь. Из-за особенностей вызова этой функции в Perl рекурсия в ней может не работать.

Предупреждение: значения $а и $Ь задаются в пакете, активном в момент вызова sort, - а он может не совпадать с пакетом, в котором была откомпилирована передаваемая sort функция сравнения (ИМЯ)! Например:



package Sort Subs,

sub revnum { $b <=> $a }

package Other Pack,

@all = sort Sort Subs revnum 4, 19, 8, 3,

Такая попытка тихо заканчивается неудачей - впрочем, при наличии ключа -w о неудаче будет заявлено вслух. Дело в том, что вызов sort создает пакетные переменные $а и $Ь в своем собственном пакете, Other Pack, а функция revnum будет использовать версии из своего пакета. Это еще один аргумент в пользу встроенных функций сортировки:

@all = sort { $b <=> $а } 4, 19 8, 3

За дополнительной информацией о пакетах обращайтесь к главе 10 «Подпрограммы».

[> Смотри также-

Описание операторов стр и <=> врег1ор{\); описание функций kill, sort и sleep вperlfunc(iy, рецепт 4.15.

4.15. Сортировка списка по вычисляемому полю

Проблема

Требуется отсортировать список, руководствуясь более сложным критерием, нежели простыми строковыми или числовыми сравнениям.

Такая проблема часто встречается при работе с объектами или сложными структурами данных («отсортировать по третьему элементу массива, на который указывает даггаая ссылка»). Кроме того, она относится к сортировке по нескольким ключам - например, когда список сортируется по дню рождения, а затем по имени (когда у нескольких людей совпадают дни рождения).

Решение

Воспользуйтесь нестандартной функцией сравнения в sort: ©ordered = sort { compareO } ©unordered,

Для ускорения работы значение поля можно вычислить заранее:

©precomputed = map { [compute(),$ ] } ©unordered, ©ordered precomputed = sort { $a->[0] <=> $b->[0] } ©precomputed, ©ordered = map { $ ->[1] } @ordered precomputed,

Наконец, эти три щага можно объединить:

©ordered = map { $ ->[1] }

sort { $а->[0] <=> $b->[0] } map { [computeO, $ ] } ©unordered.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [ 40 ] 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242