在perl中计算包含元素的数组的数量

发布于 2024-09-11 07:58:44 字数 1004 浏览 4 评论 0原文

我想我已经看这个太久了。我有一些数据,如下所示:

@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 }
);

这是一个简单的“树”数据结构。每次“深度”= 0 时,即是新“树”的开始。我想知道这些名字分别出现在多少棵树中?所需的结果将是一个以名称作为键、计数作为值的散列。

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

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

I think I've just been looking at this too long. I have some data that looks like this:

@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 }
);

This is a simple 'tree' data structure. Every time 'depth' = 0, that is the beginning of a new 'tree'. What I would like to know is in how many of these trees do each of the names appear? The desired result would be a single hash with the names as the key, and the count as the value.

The kink in this is, if you look closely, the first tree contains the name 'ethan' twice. Any tree can have any name more than once, but that should only count as 1, since they all occur in the same tree. However, 'michael' would have a count of 2, since he appears in two different trees.

I can think of a few ways of doing this, but they all involve multiple loops and seem somewhat brute force and inelegant. Hopefully, someone else out there can come up with a better solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

虚拟世界 2024-09-18 07:58:45

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

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

I think this is shortest and simplest solution

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;

Result:

alexander => 1
ava => 1
christopher => 1
emma => 1
ethan => 1
isabella => 1
joshua => 1
michael => 2
olivia => 1
sophia => 1
stephen => 2
victoria => 1
轻拂→两袖风尘 2024-09-18 07:58:45

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

The way I'd go about solving this is to use a recursive function that you map over the array. The edge case is is a depth of 0, in which case you return. otherwise, hold on to the root name, incrementing its value in a hash counter, and then recurse into the subtree where you increment that name as long as it doesn't match the root name, then recurse again, etc.

痴梦一场 2024-09-18 07:58:44

我不能 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;

也就是说,只需保留一个名称计数,只有当我们到达树的根时,这些名称才会被混入全局计数中。

I'm not 100% sure about your problem spec -- is this the correct output?

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

If so, then this code seems to do the job:

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;

that is, just keep a tally of names that only gets shuffled into the global count when we reach the root of the tree.

北凤男飞 2024-09-18 07:58:44

这是另一种方法:

#!/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;
}

Here is one more way:

#!/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;
}
無處可尋 2024-09-18 07:58:44
%count = ();
for (@a)
{
    %found = () unless $_->{depth};
    my $name = $_->{name};
    unless ($found{$name}) 
    {
        ++$count{$name};
        $found{$name} = 1;
    }
}
return %count;

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

%count = ();
for (@a)
{
    %found = () unless $_->{depth};
    my $name = $_->{name};
    unless ($found{$name}) 
    {
        ++$count{$name};
        $found{$name} = 1;
    }
}
return %count;

Basically, what we're doing is keeping a hash of the names we've found in the current tree (which is cleared out whenever the tree switches). If the current name hasn't been found yet, we bump the count and note that we've found it so it won't get counted again til the tree switches again.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文