【问题标题】:Hash::Ordered versus Tie::IxHash with JSON::XS encodeHash::Ordered 与 Tie::IxHash 与 JSON::XS 编码
【发布时间】:2016-10-27 23:14:19
【问题描述】:

我正在尝试Hash::Ordered 而不是Tie::IxHash,因为它似乎更快。

虽然Tie::IxHash 工作正常,但我在使用Hash::Ordered 时遇到了一些问题。关键是要对哈希进行排序(在 Perl 中通常是随机的)。

use Hash::Ordered;
use JSON::XS;
use Data::Dumper;

use strict;
use warnings;

my $json = JSON::XS->new;

my $oh = Hash::Ordered->new;
$oh->push('result' => { 'counter' => "123" }, 'number' => { 'num' => '55' });

my @r = $oh->as_list;

$json->pretty(1);
my $jsondata = $json->encode(\@r);
print Dumper $jsondata;

结果很奇怪:

 [
   "result",
   {
      "counter" : "123"
   },
   "number",
   {
      "num" : "55"
   }
]

这是Tie::IxHash 的工作示例,我尝试使用Hash::Ordered 获得相同的结果。

use Data::Dumper;
use Tie::IxHash;
use JSON::XS;

use strict;
use warnings;

my $json = JSON::XS->new;

my %h;
tie(%h, 'Tie::IxHash', result => { counter => "123" }, number => { num => '55' });

  $json->pretty(1);
  my $pretty_json = $json->encode(\%h);

  print Dumper $pretty_json;

输出

{
   "result" : {
      "counter" : "123"
   },
   "number" : {
      "num" : "55"
   }
}

【问题讨论】:

标签: json perl hash


【解决方案1】:

使用Hash::Ordered tied interface

my $json = JSON::XS->new;

tie my %hash, "Hash::Ordered";

$hash{'result'} = { 'counter' => "123" };
$hash{'number1'} = { 'num' => '1' };
$hash{'number2'} = { 'num' => '2' };
$hash{'number3'} = { 'num' => '3' };
$hash{'last'} = { 'num' => 'last' };

$json->pretty(1);
my $jsondata = $json->encode(\%hash);

而你得到的 JSON 数据是:

{
   "result" : {
      "counter" : "123"
   },
   "number1" : {
      "num" : "1"
   },
   "number2" : {
      "num" : "2"
   },
   "number3" : {
      "num" : "3"
   },
   "last" : {
      "num" : "last"
   }
}

【讨论】:

  • 感谢您的回复!我想我以前试过这个!当我对“as_list”使用哈希时,订单丢失了。如果您在 $oh->as_list 之后“打印 Dumper %r”,它会将 JSON 数据“结果”移动到底部。换句话说,输出是 { "number" : { "num" : "55" }, "result" : { "counter" : "123" } }。似乎只有一个数组在使用 Hash::Ordered?
【解决方案2】:

Hash::Ordered 的面向对象接口比绑定接口快得多,但某些实用程序(如$json->encode)需要真正的哈希引用

两全其美的方法是将哈希与这些实用程序结合使用,并使用tied 提取底层Hash::Ordered 对象,以便您可以使用更快的方法调用来操作它

这个简短的程序演示。这段代码唯一慢的部分是当哈希被传递给encode 以转换为 JSON 时。 push 调用不使用绑定接口并保持快速

use strict;
use warnings;

use Hash::Ordered;
use JSON::XS;

my $json = JSON::XS->new->pretty;

tie my %h, 'Hash::Ordered';
my $oh = tied %h;
$oh->push( result => { counter => 123 }, number => { num => 55 } );

print $json->encode(\%h), "\n";

输出

{
   "result" : {
      "counter" : 123
   },
   "number" : {
      "num" : 55
   }
}

【讨论】:

  • 很好的例子。我遇到了一个问题。像这样运行它: $oh->push( result => { counter => 123, z => 5, s => 8 }, number => { num => 55, p => 123 });这将丢失散列中子元素的顺序。 {"result": "counter":123,"s":8,"z":5},"number":{"p":123,"num":55}} 我如何保持这个顺序例如?
  • 我刚刚在答案中添加了解决方案。如果有更简单的方法,请随时编辑或删除我的答案。
【解决方案3】:

上面的例子可以正常工作,但是对于多维散列,需要一个额外的步骤来保持顺序。

use Hash::Ordered;
use JSON::XS;
use Data::Dumper;

use strict;
use warnings;   

sub ordered_hash_ref {
    tie my %hash, 'Hash::Ordered';
    my $oh = tied %hash;
    $oh->push(@_);
    return \%hash;
};

my $json = JSON::XS->new->pretty;
tie my %h, 'Hash::Ordered';
my $oh = tied %h;

$oh->push(result => ordered_hash_ref(counter => 123, z => 5, s => 8),  address => ordered_hash_ref(Vorname => 'Max', 
Nachname => 'Mustermann', Strasse => 'Feldweg', Hausnummer => 45));

my $pretty = $json->encode(\%h);
print Dumper $pretty;

输出

{
   "result" : {
      "counter" : 123,
      "z" : 5,
      "s" : 8
   },
   "address" : {
      "Vorname" : "Max",
      "Nachname" : "Mustermann",
      "Strasse" : "Feldweg",
      "Hausnummer" : 45
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-07
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多