sort_by函数如何工作?

时间:2011-06-08 20:16:44

标签: perl json

基于this帖子,我试图了解JSON::PPsort_by的工作原理。

当我运行此代码时

#!/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"}}

我想第一个问题是禁用最后一个outter键排序?

然后我如何掌握title的价值?算法运行时,$JSON::PP::a$JSON::PP::b包含来自同一哈希的值nametitle

我无法弄明白。任何人都可以解释这个,和/或帮我写这个算法吗?

2 个答案:

答案 0 :(得分:2)

你不能,或者至少不容易。您为sort_by提供的功能只能访问要排序的键。为了做你想做的事,你需要访问与这些键相关的值(或者更可能是键所属的hashref,所以你可以自己查找值)。这似乎是一个有用的增强;您可以提交功能请求。

如果您的数据结构足够简单(您的示例似乎是这样),您可以自己保留对哈希的引用。为此,您必须能够区分内部哈希中的键与外部哈希中的键(因此您知道要对哪个哈希进行排序,以及进行何种比较)。

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 :(得分:1)

尝试类似:

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};
};