Как работает функция sort_by? - PullRequest
0 голосов
/ 09 июня 2011

Основываясь на этом сообщении, я пытаюсь понять, как sort_by работает в JSON::PP.

Когда я запускаю этот код

#!/usr/bin/perl
use strict;
use warnings;
use JSON::PP;
use Data::Dumper qw(Dumper);

my $h = {
    22 => { title => "c", name => "d" },
    1  => { title => "1", name => "a" },
    10 => { title => "a", name => "c" },
    5  => { title => "b", name => "b" },
};

my $sorter = sub {
    # See what's going on.
    print "$JSON::PP::a cmp $JSON::PP::b\n";
    print Dumper(\@_, $_);
    <STDIN>; # press return to continue

    $JSON::PP::a cmp $JSON::PP::b
};

my $js = JSON::PP->new;
my $output = $js->sort_by($sorter)->encode($h);
print $output . "\n";

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

Прямо сейчас он выводит

{"1":{"name":"a","title":"1"},"10":{"name":"c","title":"a"},"22":{"name":"d","title":"c"},"5":{"name":"b","title":"b"}}

и что яхотелось бы закончить тем, что он отсортирован по title т.е..

{"1":{"name":"a","title":"1"},"5":{"name":"b","title":"b"}"10",{"name":"c","title":"a"},"22":{"name":"d","title":"c"}}

Полагаю, первая проблема - отключить сортировку последнего внешнего ключа?

Тогда как мне это сделать?получить значение title?Когда алгоритм работает, $JSON::PP::a и $JSON::PP::b содержат значения name и title из того же хэша.

Это я не могу понять.Кто-нибудь может объяснить это и / или помочь мне написать этот алгоритм?

Ответы [ 2 ]

2 голосов
/ 09 июня 2011

Вы не можете или, по крайней мере, не легко.Функция, которую вы даете sort_by, имеет доступ только к сортируемым клавишам.Для того, чтобы делать то, что вы хотите, вам нужно иметь доступ к значениям, связанным с этими ключами (или, что более вероятно, к хэш-функции, к которой принадлежат ключи, чтобы вы могли искать значения самостоятельно).Кажется, это было бы полезным улучшением;Вы можете отправить запрос на добавление функции.

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

my $sorter = sub {
    if ($JSON::PP::a =~ /^\d+$/) {
      return $h->{$JSON::PP::a}{title} cmp $h->{$JSON::PP::b}{title};
    }
    return $JSON::PP::a cmp $JSON::PP::b
};
1 голос
/ 09 июня 2011

Попробуйте что-то вроде:

my $sorter = sub {
    my $h = $_[0];

    # simple check for if we are too deep
    # just sort by keys in that case
    return $JSON::PP::a cmp $JSON::PP::b
        if ref($h->{$JSON::PP::a}) ne 'HASH';

    # sort by titles value
    return $h->{$JSON::PP::a}{title} cmp $h->{$JSON::PP::b}{title};
};

$_[0] - это хэш, который в настоящее время сортируется, хотя, похоже, это не задокументировано (возможно, ненадежно).

Это работает для этогослучай, но более сложные структуры будут иметь проблемы, так как проверка глубины очень проста.Лучше проверить тип ключа, например cjm, если вы уверены, что нет более глубоких ключей этого типа.Или комбинация, например:

my $sorter = sub {
    my $h = $_[0];

    # just sort by the keys
    return $JSON::PP::a cmp $JSON::PP::b
        unless $JSON::PP::a =~ /^\d+\z/
            && $JSON::PP::b =~ /^\d+\z/
            && ref($h->{$JSON::PP::a}) eq 'HASH'
            && ref($h->{$JSON::PP::b}) eq 'HASH';

    # sort by titles
    return $h->{$JSON::PP::a}{title} cmp $h->{$JSON::PP::b}{title};
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...