Perl:如何按照除“根”键属性之外的其他内容对JSON结构进行排序

9

Perl: 如何使用JSON::PP对复杂结构进行排序?

来自JSON文档:

由于排序例程在JSON::PP范围内运行,所以给定的子例程名称和特殊变量$a、$b将以'JSON::PP::'开头。

这是我的尝试,似乎不起作用。

open my $fh, ">", $file or warn " exportAsJSON: can't open file: '$file': $!";
print $fh  $coder->sort_by(sub {$_->{column_def}->{$JSON::PP::a} cmp $_->{column_def}->{$JSON::PP::b}  } )->encode(\%json);
close $fh;

我希望按照关键字排序,然后按照下面"column_def"属性的属性关键字进行排序,即密度、深度和磁性矿物含量:

{
    "column_def":
        {
            "depth_in_m":
                {
                    "names":"depth_in_m",
                    "pos":"0"
                },
            "mag_sus":
                {
                    "names":
                        {
                            "A_ALIAS":"Mag-Sus.",
                            "A_DESC":"magnetic susceptibility in SI",
                            "ATTRIBUTE":"MAG_SUS"
                        },
                    "pos":"2"
                },
            "density":
                {
                    "names":
                        {
                            "A_ALIAS":"Density",
                            "A_DESC":"density in gm\/cc",
                            "ATTRIBUTE":"DENSITY"
                        },
                    "pos":"1"
                }
        },
    "data":
        {
            "depth_in_m":"14.635",
            "mag_sus":"n.a.",
            "density":"n.a."
        }
}

3
我很好奇为什么你要对一个将被解析为哈希表的东西进行排序——因为哈希表本身没有固有的顺序。 - Matt Ball
1
@熊会吃掉你:实际上,内存中的表示没有固有的排序。我想将排序后的哈希结构保存到文件(或临时文件),以进行差异比较和可视化检查(以及更复杂的操作)。 - knb
1个回答

16

我不确定你希望如何对JSON输出进行排序,除了按哈希键排序以外。如果这就是你想要的,只需向canonical方法传递一个true参数。

use strict;
use warnings;

use JSON::PP;

# A simple hash-of-hashes for exploration.
my $h = {
    Z => { c => 1, d => 2 },
    A => { a => 3, r => 4 },
    B => { c => 5, x => 6 },
    S => { q => 7, d => 8 },
};

my $js = JSON::PP->new;
$js->canonical(1);

my $output = $js->encode($h);
print $output;

如果您使用了sort_by方法,则在sort块中使用$_没有意义:它代表什么?从文档中并不清楚sort_by代码将接收哪些参数。可以像这样使用Data::Dumper

use Data::Dumper qw(Dumper);

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

    # Sort hash keys alphabetically.
    $JSON::PP::a cmp $JSON::PP::b;
};

my $output = $js->sort_by($sorter)->encode($h);

你可以推断出sort_by的工作原理如下:(1)它接收两个参数,即当前正在处理的 JSON::PP 对象和哈希引用;(2)$JSON::PP::a$JSON::PP::b变量保存了当前比较的哈希键。但是请注意,哈希引用是指向从叶节点向上构建的 JSON 输出的,而不是指向您原始数据结构的。这似乎使得编写比较器的任务有些棘手。祝你好运。

my $sorter = sub {
    my ($json_pp_object, $hash_ref) = @_;

    # Write your own comparator here.
};

my $output = $js->sort_by($sorter)->encode($h);

预期排序: 首先按照哈希键的字母顺序, 其次按照第一个哈希引用子键的字母顺序。或者替代方案(第二个), 根据“pos”的值进行数字排序(在弄清楚嵌套结构的排序方式后)。 - knb
个人笔记:这是一个类似的问题:https://dev59.com/j2855IYBdhLWcg3w_5mm - knb
1
在编写自己的排序器时需要注意。似乎 $JSON::PP::VERSION = '2.27200' 并不会将 JSON::PP 对象作为第一个参数传递。对于最后一个示例,版本 >= 2.27200 的排序器需要使用 my $hashref = shift; - heymatthew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接