Как я могу отсортировать массив Perl из массива хэшей? - PullRequest
0 голосов
/ 24 марта 2010
@aoaoh;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}

Вывод:

    22=31
    21=31
    23=17

но я ожидаю, что это будет

    21=31
    22=31
    23=17

Пожалуйста, скажите мне, где это неправильно.

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

    23=17 
    22=31
    21=31 (if 2 keys have same value then key with higher value come first)

Ответы [ 4 ]

1 голос
/ 24 марта 2010

Звучит так, как вы хотите:

for $val (sort keys %{$aoaoh[$i][$k]}) {

и

for $val (reverse sort keys %{$aoaoh[$i][$k]}) {

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

for $val (sort {$aoaoh[$i][$k]->{$a} <=> $aoaoh[$i][$k]->{$b} || $a <=> $b} keys %{$aoaoh[$i][$k]}) {
0 голосов
/ 30 мая 2011

Ответ за Q1 будет:

print "${$aoaoh[0][0]}{$_}=$_\n" for sort keys %{$aoaoh[0][0]};

что можно записать как:

for (sort keys %{$aoaoh[0][0]}) {
    print "${$aoaoh[0][0]}{$_}=$_\n"
}

И ответ на Q2:

print "$_->[1]=$_->[0]\n" for
map { [$_->[0], $_->[1]] }
sort { $a->[0] cmp $b->[0] }
map { [ ${$aoaoh[0][0]}{$_}, $_ ] } keys %{$aoaoh[0][0]};
0 голосов
/ 25 марта 2010

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

Из ответа perlfaq4 на Как отсортировать массив по чему-либо ?


Предоставить функцию сравнения для sort () (описана в sort в perlfunc):

@list = sort { $a <=> $b } @list;

Функция сортировки по умолчанию - cmp, сравнение строк, которая сортирует (1, 2, 10) в (1, 10, 2). <=>, использованный выше, является оператором числового сравнения.

Если у вас есть сложная функция, необходимая для извлечения части, по которой вы хотите отсортировать, то не делайте это внутри функции сортировки. Сначала вытащите его, потому что сортировка BLOCK может вызываться много раз для одного и того же элемента. Вот пример того, как вытащить первое слово после первого числа в каждом элементе, а затем отсортировать эти слова без учета регистра.

@idx = ();
for (@data) {
    ($item) = /\d+\s*(\S+)/;
    push @idx, uc($item);
    }
@sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];

, который также можно записать таким образом, используя уловку, известную как преобразование Шварца:

@sorted = map  { $_->[0] }
    sort { $a->[1] cmp $b->[1] }
    map  { [ $_, uc( (/\d+\s*(\S+)/)[0]) ] } @data;

Если вам нужно отсортировать несколько полей, полезна следующая парадигма.

@sorted = sort {
    field1($a) <=> field1($b) ||
    field2($a) cmp field2($b) ||
    field3($a) cmp field3($b)
    } @data;

Это удобно сочетать с предварительным расчетом ключей, как указано выше.

Подробнее об этом подходе см. В статье сортировки в коллекции «Гораздо больше, чем вы хотели знать» в http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz

См. Также вопрос позже в perlfaq4 о сортировке хэшей.

0 голосов
/ 24 марта 2010

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

Вы можете либо реализовать более сложную структуру данных, которая обрабатывает некоторые упорядочения для вас, либо добавить на экран более логику сортировки (вместо просто зацикливания), либо загрузить модуль для поддержки упорядоченных хешей, таких как * * Tie :: Hash :: 1003 индексируются .

Я ожидаю, что реализация Tie :: Hash :: Indexed будет выглядеть так:

my @aoaoh;

use Tie::Hash::Indexed;
tie my %hash, 'Tie::Hash::Indexed';
$aoaoh[0][0] = \%hash;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}
...