将哈希与数组组合用于某些键

时间:2016-09-23 19:11:05

标签: arrays perl hash

我是perl的新手,我已经坚持了几天。希望你能帮帮我。

我使用两个文件,我将简化,因为我必须事先处理它们:

file_one的{​​{1}}列表{name1,name_2,name_3 ...)和names(number_1,number_2,number_3 ...)分别关联

numbers列有file_two(number_2和number_6)和numbers(item_a,item_b与number_2相关联,item_b,item_c与number_6相关联)

我的想法是对两个文件进行哈希并将它们组合起来。我遇到的问题是当我需要将项目列表加入哈希(数组的哈希)然后使用它时。所以第一个哈希工作正常,但第二个哈希有问题。

我尝试使用items,但由于我使用的引用,我不知道如何将它与另一个结合起来。

最后的任务是比较两个名字,以便获得他们共享的项目。如果可以使用perl并且如果可能的话不使用模块,那将会很棒。

非常感谢

2 个答案:

答案 0 :(得分:2)

如果我正确理解你,你就有这个:

foo => 1
bar => 2
baz => 3

然后你有:

2 => a, b
3 => b, c

您想了解barbaz分享的内容(例如)。

一种选择是将它们放在SQLite数据库中的两个表中并使用SQL。这可以是处理这样的关系数据的最简单,最灵活,最高效的方式。特别是如果它有很多,特别是如果你想对它做很多不同的搜索。这避免了必须编写一堆自定义代码和可能日益复杂的数据结构。

在Perl中完成它,这是一个草图。

首先,将包含叶子(项目不指向任何其他内容)的第二个文件读入数组的哈希值。你结束了这样的结构:

$nums2items{2} = [qw(a, b)];

然后将第一个文件读入哈希,但不是将数字存储为值,而是存储%nums2items个引用。

$names2items{foo} = $nums2items{1};

现在,如果您想检查barbaz是否共享任何内容,您可以获取数组并找到与Array::Utils的交集。

use Array::Utils qw(intersect);

print join ", ", intersect( @{$names2items{bar}}, @{$names2items{baz}});

如果您要做很​​多事情,并且项目的顺序无关紧要,那么将项目存储为哈希会更有效。这避免了必须对两个列表进行排序和比较。这就是intersect无论如何,将一个列表转换为一个哈希(或一组)并将其与另一个列表进行比较。

use strict;
use warnings;
use v5.10;

my %nums2items = (
    2   => { a => 1, b => 1,         d => 1 },
    3   => {         b => 1, c => 1, d => 1, e => 1 },
);
my %names2nums = (
    bar => $nums2items{2},
    baz => $nums2items{3}
);

# Take the intersection in O(n) time.
say join ", ", grep { $names2nums{bar}{$_} } keys %{$names2nums{baz}};

使用像那样的哈希,其中键是事物而值是1,是表示集合的一种非常常见且有效的方式。

或者您可以使用Set::Tiny模块。这非常直截了当。如果你想学习如何在Perl中使用集合,我强烈建议你阅读它的来源。

答案 1 :(得分:0)

从您对Schwern的评论看来,您的文件看起来像这样:

foo, 1
bar, 2
biz, 3
bas, 4

1, jacks blue horse
2, the green horse
3, jacks
4, bing

并且您成功地将它们读入两个哈希值,其中以逗号作为键之前的值以及之后的值作为值。现在你要采取明智的措辞,打印出他们共同的话语。您不想使用任何模块,而是使用原始Perl。

首先,为什么第二个是数组数组而不是哈希值,如果它是数字键控的话?

其次,你为什么要合并它们?为什么不使用嵌套循环:

my @key_list = keys %hash_1;
while ( @key_list )
   {
   my $curr_key = shift @key_list;
   for my $next_key ( @key_list )
      {
      my @curr_list = @{$hash_2{$hash_1{$curr_key}}};
      my @next_list = @{$hash_2{$hash_1{$next_key}}};
      while ( @curr_list )
         {
         my $curr_word = shift @curr_list;
         for my $next_word ( @next_list )
            {
            print "$curr_key and $next_key share $curr_word\n"
               if $curr_word eq $next_word;
            }
         }
      }
   }

这有点蛮力,但它可以完成工作。相反,你可以使用优秀的Set :: modules。了解和使用像Perl或C ++这样的现代语言的一部分就是了解标准库和通用库并使用它们。