NAME Acme::CPANModules::OrderedHash - List of modules that provide ordered hash data type VERSION This document describes version 0.004 of Acme::CPANModules::OrderedHash (from Perl distribution Acme-CPANModules-OrderedHash), released on 2025-04-15. SYNOPSIS To run benchmark with default option: % bencher --cpanmodules-module OrderedHash To run module startup overhead benchmark: % bencher --module-startup --cpanmodules-module OrderedHash For more options (dump scenario, list/include/exclude/add participants, list/include/exclude/add datasets, etc), see bencher or run "bencher --help". DESCRIPTION When you ask a Perl's hash for the list of keys, the answer comes back unordered. In fact, Perl explicitly randomizes the order of keys it returns everytime. The random ordering is a (security) feature, not a bug. However, sometimes you want to know the order of insertion. These modules provide you with an ordered hash; most of them implement it by recording the order of insertion of keys in an additional array. Other related modules: Tie::SortHash - will automatically sort keys when you call keys(), values(), each(). But this module does not maintain insertion order. ACME::CPANMODULES ENTRIES Tie::IxHash Hash::Ordered Tie::Hash::Indexed Provides two interfaces: tied hash and OO. Tie::LLHash Tie::StoredOrderHash Array::OrdHash Provide something closest to PHP's associative array, where you can refer elements by key or by numeric index, and insertion order is remembered. List::Unique::DeterministicOrder Provide a list, not hash. Tree::RB::XS Multi-purpose tree data structure which can record insertion order and act as an ordered hash. Use "track_recent => 1, keys_in_recent_order => 1" options. Can be used as a tied hash, or as an object (faster). BENCHMARKED MODULES Version numbers shown below are the versions used when running the sample benchmark. Tie::IxHash 1.23 Hash::Ordered 0.014 Tie::Hash::Indexed 0.08 Tie::LLHash 1.004 Tie::StoredOrderHash 0.22 Array::OrdHash 1.03 Tree::RB::XS 0.19 BENCHMARK PARTICIPANTS * Tie::IxHash (perl_code) Tie::IxHash * Hash::Ordered (perl_code) Hash::Ordered * Tie::Hash::Indexed (perl_code) Tie::Hash::Indexed * Tie::LLHash (perl_code) Tie::LLHash * Tie::StoredOrderHash (perl_code) Tie::StoredOrderHash * Array::OrdHash (perl_code) Array::OrdHash * Tree::RB::XS (perl_code) Tree::RB::XS BENCHMARK DATASETS * insert 1000 pairs * insert 1000 pairs + delete * insert 1000 pairs + return keys 100 times * insert 1000 pairs + iterate 10 times BENCHMARK SAMPLE RESULTS Sample benchmark #1 Run on: perl: *v5.40.1*, CPU: *AMD Ryzen 5 7535HS with Radeon Graphics (6 cores)*, OS: *GNU/Linux Ubuntu version 24.10*, OS kernel: *Linux version 6.11.0-8-generic*. Benchmark command (default options): % bencher --cpanmodules-module OrderedHash Result formatted as table (split, part 1 of 4): #table1# {dataset=>"insert 1000 pairs"} +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | participant | rate (/s) | time (ms) | pct_faster_vs_slowest | pct_slower_vs_fastest | errors | samples | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | Tie::StoredOrderHash | 539 | 1.85 | 0.00% | 528.45% | 1.4e-06 | 22 | | Tie::LLHash | 640 | 1.6 | 19.19% | 427.28% | 3.4e-06 | 20 | | Array::OrdHash | 889 | 1.12 | 64.84% | 281.24% | 9.6e-07 | 20 | | Tie::IxHash | 1080 | 0.928 | 99.73% | 214.65% | 6.1e-07 | 20 | | Hash::Ordered | 1460 | 0.684 | 170.98% | 131.92% | 4.1e-07 | 20 | | Tie::Hash::Indexed | 1600 | 0.62 | 196.91% | 111.67% | 9.6e-07 | 20 | | Tree::RB::XS | 3400 | 0.3 | 528.45% | 0.00% | 5.4e-07 | 21 | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ The above result formatted in Benchmark.pm style: Rate T:S T:L A:O T:I H:O TH:I TR:X T:S 539/s -- -13% -39% -49% -63% -66% -83% T:L 640/s 15% -- -29% -42% -57% -61% -81% A:O 889/s 65% 42% -- -17% -38% -44% -73% T:I 1080/s 99% 72% 20% -- -26% -33% -67% H:O 1460/s 170% 133% 63% 35% -- -9% -56% TH:I 1600/s 198% 158% 80% 49% 10% -- -51% TR:X 3400/s 516% 433% 273% 209% 128% 106% -- Legends: A:O: participant=Array::OrdHash H:O: participant=Hash::Ordered T:I: participant=Tie::IxHash T:L: participant=Tie::LLHash T:S: participant=Tie::StoredOrderHash TH:I: participant=Tie::Hash::Indexed TR:X: participant=Tree::RB::XS The above result presented as chart: Result formatted as table (split, part 2 of 4): #table2# {dataset=>"insert 1000 pairs + delete"} +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | participant | rate (/s) | time (ms) | pct_faster_vs_slowest | pct_slower_vs_fastest | errors | samples | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | Tie::IxHash | 31 | 32 | 0.00% | 5838.76% | 4.8e-05 | 21 | | Tie::StoredOrderHash | 310 | 3.3 | 875.00% | 509.10% | 8.6e-06 | 21 | | Tie::LLHash | 376 | 2.66 | 1098.31% | 395.59% | 2.5e-06 | 20 | | Array::OrdHash | 440 | 2.3 | 1289.81% | 327.31% | 6.1e-06 | 20 | | Hash::Ordered | 610 | 1.6 | 1854.01% | 203.93% | 1.9e-06 | 20 | | Tie::Hash::Indexed | 1060 | 0.946 | 3272.21% | 76.11% | 5.7e-07 | 20 | | Tree::RB::XS | 1900 | 0.54 | 5838.76% | 0.00% | 6.3e-07 | 20 | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ The above result formatted in Benchmark.pm style: Rate T:I T:S T:L A:O H:O TH:I TR:X T:I 31/s -- -89% -91% -92% -95% -97% -98% T:S 310/s 869% -- -19% -30% -51% -71% -83% T:L 376/s 1103% 24% -- -13% -39% -64% -79% A:O 440/s 1291% 43% 15% -- -30% -58% -76% H:O 610/s 1900% 106% 66% 43% -- -40% -66% TH:I 1060/s 3282% 248% 181% 143% 69% -- -42% TR:X 1900/s 5825% 511% 392% 325% 196% 75% -- Legends: A:O: participant=Array::OrdHash H:O: participant=Hash::Ordered T:I: participant=Tie::IxHash T:L: participant=Tie::LLHash T:S: participant=Tie::StoredOrderHash TH:I: participant=Tie::Hash::Indexed TR:X: participant=Tree::RB::XS The above result presented as chart: Result formatted as table (split, part 3 of 4): #table3# {dataset=>"insert 1000 pairs + iterate 10 times"} +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | participant | rate (/s) | time (ms) | pct_faster_vs_slowest | pct_slower_vs_fastest | errors | samples | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ | Tie::StoredOrderHash | 71 | 14 | 0.00% | 508.52% | 2e-05 | 20 | | Tie::LLHash | 75.4 | 13.3 | 5.52% | 476.69% | 1.2e-05 | 24 | | Array::OrdHash | 87.2 | 11.5 | 22.04% | 398.65% | 1e-05 | 20 | | Tie::IxHash | 107 | 9.36 | 49.51% | 307.02% | 2.5e-06 | 20 | | Tie::Hash::Indexed | 171 | 5.85 | 139.18% | 154.42% | 5e-06 | 21 | | Hash::Ordered | 250 | 4 | 250.17% | 73.78% | 6.1e-06 | 20 | | Tree::RB::XS | 435 | 2.3 | 508.52% | 0.00% | 8.2e-07 | 20 | +----------------------+-----------+-----------+-----------------------+-----------------------+---------+---------+ The above result formatted in Benchmark.pm style: Rate T:S T:L A:O T:I TH:I H:O TR:X T:S 71/s -- -4% -17% -33% -58% -71% -83% T:L 75.4/s 5% -- -13% -29% -56% -69% -82% A:O 87.2/s 21% 15% -- -18% -49% -65% -80% T:I 107/s 49% 42% 22% -- -37% -57% -75% TH:I 171/s 139% 127% 96% 60% -- -31% -60% H:O 250/s 250% 232% 187% 134% 46% -- -42% TR:X 435/s 508% 478% 400% 306% 154% 73% -- Legends: A:O: participant=Array::OrdHash H:O: participant=Hash::Ordered T:I: participant=Tie::IxHash T:L: participant=Tie::LLHash T:S: participant=Tie::StoredOrderHash TH:I: participant=Tie::Hash::Indexed TR:X: participant=Tree::RB::XS The above result presented as chart: Result formatted as table (split, part 4 of 4): #table4# {dataset=>"insert 1000 pairs + return keys 100 times"} +----------------------+-----------+-----------+-----------------------+-----------------------+-----------+---------+ | participant | rate (/s) | time (ms) | pct_faster_vs_slowest | pct_slower_vs_fastest | errors | samples | +----------------------+-----------+-----------+-----------------------+-----------------------+-----------+---------+ | Tie::StoredOrderHash | 17 | 58 | 0.00% | 1439.14% | 6.1e-05 | 20 | | Tie::LLHash | 20 | 50 | 16.39% | 1222.37% | 7.3e-05 | 20 | | Array::OrdHash | 25 | 40 | 44.54% | 964.81% | 0.00011 | 21 | | Tie::IxHash | 26.8 | 37.3 | 54.99% | 893.08% | 3.3e-05 | 20 | | Tie::Hash::Indexed | 44 | 23 | 154.54% | 504.67% | 2.7e-05 | 20 | | Hash::Ordered | 135 | 7.43 | 678.48% | 97.71% | 7.1e-06 | 20 | | Tree::RB::XS | 270 | 3.8 | 1439.14% | 0.00% | 4.3e-06 | 20 | +----------------------+-----------+-----------+-----------------------+-----------------------+-----------+---------+ The above result formatted in Benchmark.pm style: Rate T:S T:L A:O T:I TH:I H:O TR:X T:S 17/s -- -13% -31% -35% -60% -87% -93% T:L 20/s 15% -- -19% -25% -54% -85% -92% A:O 25/s 44% 25% -- -6% -42% -81% -90% T:I 26.8/s 55% 34% 7% -- -38% -80% -89% TH:I 44/s 152% 117% 73% 62% -- -67% -83% H:O 135/s 680% 572% 438% 402% 209% -- -48% TR:X 270/s 1426% 1215% 952% 881% 505% 95% -- Legends: A:O: participant=Array::OrdHash H:O: participant=Hash::Ordered T:I: participant=Tie::IxHash T:L: participant=Tie::LLHash T:S: participant=Tie::StoredOrderHash TH:I: participant=Tie::Hash::Indexed TR:X: participant=Tree::RB::XS The above result presented as chart: Sample benchmark #2 Benchmark command (benchmarking module startup overhead): % bencher --cpanmodules-module OrderedHash --module-startup Result formatted as table: #table5# +----------------------+-----------+-------------------+-----------------------+-----------------------+-----------+---------+ | participant | time (ms) | mod_overhead_time | pct_faster_vs_slowest | pct_slower_vs_fastest | errors | samples | +----------------------+-----------+-------------------+-----------------------+-----------------------+-----------+---------+ | Hash::Ordered | 14 | 6 | 0.00% | 80.85% | 0.00011 | 20 | | Tie::Hash::Indexed | 13 | 5 | 3.99% | 73.91% | 9.5e-05 | 21 | | Array::OrdHash | 13 | 5 | 9.26% | 65.51% | 9.4e-05 | 20 | | Tree::RB::XS | 12 | 4 | 9.34% | 65.39% | 9.6e-05 | 20 | | Tie::LLHash | 12 | 4 | 12.48% | 60.77% | 8.7e-05 | 20 | | Tie::IxHash | 12 | 4 | 13.93% | 58.73% | 3.8e-05 | 20 | | Tie::StoredOrderHash | 10 | 2 | 39.06% | 30.05% | 0.0001 | 20 | | perl -e1 (baseline) | 8 | 0 | 80.85% | 0.00% | 7.8e-05 | 21 | +----------------------+-----------+-------------------+-----------------------+-----------------------+-----------+---------+ The above result formatted in Benchmark.pm style: Rate H:O TH:I A:O TR:X T:L T:I T:S perl -e1 (baseline) H:O 71.4/s -- -7% -7% -14% -14% -14% -28% -42% TH:I 76.9/s 7% -- 0% -7% -7% -7% -23% -38% A:O 76.9/s 7% 0% -- -7% -7% -7% -23% -38% TR:X 83.3/s 16% 8% 8% -- 0% 0% -16% -33% T:L 83.3/s 16% 8% 8% 0% -- 0% -16% -33% T:I 83.3/s 16% 8% 8% 0% 0% -- -16% -33% T:S 100.0/s 39% 30% 30% 19% 19% 19% -- -19% perl -e1 (baseline) 125.0/s 75% 62% 62% 50% 50% 50% 25% -- Legends: A:O: mod_overhead_time=5 participant=Array::OrdHash H:O: mod_overhead_time=6 participant=Hash::Ordered T:I: mod_overhead_time=4 participant=Tie::IxHash T:L: mod_overhead_time=4 participant=Tie::LLHash T:S: mod_overhead_time=2 participant=Tie::StoredOrderHash TH:I: mod_overhead_time=5 participant=Tie::Hash::Indexed TR:X: mod_overhead_time=4 participant=Tree::RB::XS perl -e1 (baseline): mod_overhead_time=0 participant=perl -e1 (baseline) The above result presented as chart: To display as an interactive HTML table on a browser, you can add option "--format html+datatables". FAQ What is an Acme::CPANModules::* module? An Acme::CPANModules::* module, like this module, contains just a list of module names that share a common characteristics. It is a way to categorize modules and document CPAN. See Acme::CPANModules for more details. What are ways to use this Acme::CPANModules module? Aside from reading this Acme::CPANModules module's POD documentation, you can install all the listed modules (entries) using cpanm-cpanmodules script (from App::cpanm::cpanmodules distribution): % cpanm-cpanmodules -n OrderedHash Alternatively you can use the cpanmodules CLI (from App::cpanmodules distribution): % cpanmodules ls-entries OrderedHash | cpanm -n or Acme::CM::Get: % perl -MAcme::CM::Get=OrderedHash -E'say $_->{module} for @{ $LIST->{entries} }' | cpanm -n or directly: % perl -MAcme::CPANModules::OrderedHash -E'say $_->{module} for @{ $Acme::CPANModules::OrderedHash::LIST->{entries} }' | cpanm -n This Acme::CPANModules module contains benchmark instructions. You can run a benchmark for some/all the modules listed in this Acme::CPANModules module using the bencher CLI (from Bencher distribution): % bencher --cpanmodules-module OrderedHash This Acme::CPANModules module also helps lcpan produce a more meaningful result for "lcpan related-mods" command when it comes to finding related modules for the modules listed in this Acme::CPANModules module. See App::lcpan::Cmd::related_mods for more details on how "related modules" are found. HOMEPAGE Please visit the project's homepage at . SOURCE Source repository is at . SEE ALSO Acme::CPANModules::HashUtilities Acme::CPANModules - about the Acme::CPANModules namespace cpanmodules - CLI tool to let you browse/view the lists AUTHOR perlancar CONTRIBUTOR Michael Conrad CONTRIBUTING To contribute, you can send patches by email/via RT, or send pull requests on GitHub. Most of the time, you don't need to build the distribution yourself. You can simply modify the code, then test via: % prove -l If you want to build the distribution (e.g. to try to install it locally on your system), you can install Dist::Zilla, Dist::Zilla::PluginBundle::Author::PERLANCAR, Pod::Weaver::PluginBundle::Author::PERLANCAR, and sometimes one or two other Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond that are considered a bug and can be reported to me. COPYRIGHT AND LICENSE This software is copyright (c) 2025 by perlancar . This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. BUGS Please report any bugs or feature requests on the bugtracker website When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.