【问题标题】:Computing number of arrays containing an element in perl在 perl 中计算包含元素的数组的数量
【发布时间】:2010-07-26 20:49:36
【问题描述】:

我想我只是看这个太久了。我有一些看起来像这样的数据:

@a = (
    { name => 'ethan', depth => 0 },
    { name => 'victoria', depth => 1 },
    { name => 'stephen', depth => 2 },
    { name => 'christopher', depth => 3 },
    { name => 'isabella', depth => 2 },
    { name => 'ethan', depth => 3 },
    { name => 'emma', depth => 0 },
    { name => 'michael', depth => 1 },
    { name => 'olivia', depth => 2 },
    { name => 'alexander', depth => 3 },
    { name => 'stephen', depth => 1 },
    { name => 'sophia', depth => 0 },
    { name => 'michael', depth => 1 },
    { name => 'ava', depth => 1 },
    { name => 'joshua', depth => 2 }
);

这是一个简单的“树”数据结构。每次'depth' = 0,那是一个新的'树'的开始。我想知道的是,每个名字出现在这些树中有多少棵?期望的结果是一个以名称为键、计数为值的散列。

其中的问题是,如果您仔细观察,第一棵树包含两个名称“ethan”。任何一棵树都可以有多个名字,但这只能算作 1,因为它们都出现在同一棵树中。但是,“michael”的计数为 2,因为他出现在两棵不同的树中。

我可以想到几种方法来做到这一点,但它们都涉及多个循环,并且看起来有些蛮力和不优雅。希望其他人可以提出更好的解决方案。

【问题讨论】:

  • 选择这种结构来表示一棵树有什么特别的原因吗?我能想到一些更直观的格式。 :)
  • 它主要是一种输出格式——它不需要太多的“树”功能,只需要每个条目缩进多少。我没有预见到一旦我发布了这个工具,我的同事会要求更多的功能,或者我一开始会把它表示为一棵树。

标签: perl arrays hash tree intersection


【解决方案1】:

我不能 100% 确定您的问题规范 - 这是正确的输出吗?

  alexander 1
        ava 1
christopher 1
       emma 1
      ethan 1
   isabella 1
     joshua 1
    michael 2
     olivia 1
     sophia 1
    stephen 2
   victoria 1

如果是这样,那么这段代码似乎可以完成这项工作:

my @names = (
  # your @a above
);

my (%seen, %count);

for my $entry (@names) {
  if ($entry->{depth} == 0) {
    ++$count{$_} for keys %seen;
    %seen = ();
  }
  ++$seen{ $entry->{name} };
}

++$count{$_} for keys %seen;
print "$_\t$count{$_}\n" for sort keys %count;

也就是说,只保留一个只有在我们到达树根时才会被打乱到全局计数中的名称的计数。

【讨论】:

  • 这段代码不会错过每棵树中的“根”条目吗?我认为您需要说 %seen = ( $entry->{name} => 1 ) 而不是 %seen = ()
  • @coding_hero:是吗?我没有看到 emmasophia 的计数在哪里。
  • @cHao - 你是对的。我主要扫描列表中的值 > 1 以查看他是否明白了这一点。我没有寻找每个名字。
【解决方案2】:

这里还有一种方法:

#!/usr/bin/perl

use strict; use warnings;

my @data = (
    { name => 'ethan', depth => 0 },
    { name => 'victoria', depth => 1 },
    { name => 'stephen', depth => 2 },
    { name => 'christopher', depth => 3 },
    { name => 'isabella', depth => 2 },
    { name => 'ethan', depth => 3 },
    { name => 'emma', depth => 0 },
    { name => 'michael', depth => 1 },
    { name => 'olivia', depth => 2 },
    { name => 'alexander', depth => 3 },
    { name => 'stephen', depth => 1 },
    { name => 'sophia', depth => 0 },
    { name => 'michael', depth => 1 },
    { name => 'ava', depth => 1 },
    { name => 'joshua', depth => 2 }
);

my @trees;

for my $x ( @data ) {
    push @trees, {} unless $x->{depth};
    $trees[-1]->{ $x->{name} } = undef;
}

my @names = keys %{ { map { $_->{name} => undef } @data } };
for my $name ( sort @names ) {
    printf "%s appears in %d tree(s)\n",
        $name, scalar grep { exists $_->{$name} } @trees;
}

【讨论】:

    【解决方案3】:
    %count = ();
    for (@a)
    {
        %found = () unless $_->{depth};
        my $name = $_->{name};
        unless ($found{$name}) 
        {
            ++$count{$name};
            $found{$name} = 1;
        }
    }
    return %count;
    

    基本上,我们所做的是保留我们在当前树中找到的名称的哈希(每当树切换时都会清除该哈希)。如果尚未找到当前名称,我们会增加计数并注意我们已找到它,因此在树再次切换之前不会再次计数。

    【讨论】:

      【解决方案4】:

      我认为这是最短最简单的解决方案

      my (%count, %seen);
      for my $e (@a) {
        %seen = () unless $e->{depth};
        $count{$e->{name}}++ unless $seen{$e->{name}}++;
      }
      
      print "$_ => $count{$_}\n" for sort keys %count;
      

      结果:

      alexander => 1
      ava => 1
      christopher => 1
      emma => 1
      ethan => 1
      isabella => 1
      joshua => 1
      michael => 2
      olivia => 1
      sophia => 1
      stephen => 2
      victoria => 1
      

      【讨论】:

        【解决方案5】:

        我要解决这个问题的方法是使用您映射到数组上的递归函数。边缘情况是深度为 0,在这种情况下您返回。否则,保留根名称,在哈希计数器中增加其值,然后递归到子树中,只要它与根名称不匹配,就增加该名称,然后再次递归,等等。

        【讨论】:

        • 有点太复杂了。除非规范发生变化,否则您不需要递归。
        • @cHao:嗯,这取决于规范。如果子树本身可以包含子树,那么您需要做一些至少类似于递归的事情
        • 不,没那么复杂。基本上就是我上面概述的。
        • 因此“除非规格发生变化”。现在,只有 0 表示我们在新树中。
        • 我当时误解了 OP。这似乎暗示该结构可以嵌套。如果它是平坦的,那么不,你不需要递归。
        猜你喜欢
        • 2020-02-03
        • 1970-01-01
        • 1970-01-01
        • 2012-04-28
        • 1970-01-01
        • 2010-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多