在 Perl 中计算稀疏数组中的元素

Posted

技术标签:

【中文标题】在 Perl 中计算稀疏数组中的元素【英文标题】:Counting elements in a sparse array in Perl 【发布时间】:2010-10-26 04:38:00 【问题描述】:

如何获取数组中的总项,而不是最后一个 id?

我发现有两种方法都行不通:

my @a;
# Add some elements (no consecutive ids)
$a[0]= '1';
$a[5]= '2';
$a[23]= '3';

print $#a, "\n"; # Prints 23
print scalar(@a), "\n"; # Prints 24

我预计会得到 3 个...

【问题讨论】:

【参考方案1】:

编辑:哈希与数组

正如 cincodenada 在评论中正确指出的那样,ysth 给出了更好的答案:我应该用另一个问题来回答你的问题:“你真的想使用 Perl 数组吗?散列可能更合适。”

数组为所有可能的索引分配内存,直到目前使用的最大索引。在您的示例中,您分配了 24 个单元格(但仅使用 3 个)。相比之下,散列只为那些实际使用的字段分配空间。

数组解决方案:标量 grep

这里有两种可能的解决方案(解释见下文):

print scalar(grep defined $_ @a), "\n";  # prints 3
print scalar(grep $_, @a), "\n";            # prints 3

说明:在添加$a[23] 之后,您的数组确实包含 24 个元素 --- 但其中大多数是未定义的(也计算为 false)。您可以计算已定义元素的数量(如第一个解决方案中所做的那样)或真实元素的数量(第二个解决方案)。

有什么区别?如果您设置$a[10]=0,那么第一个解决方案将计算它,但第二个解决方案不会(因为 0 为假但已定义)。如果您设置$a[3]=undef,则没有一个解决方案会计算它。

哈希解决方案(by yst)

根据另一个解决方案的建议,您可以使用哈希并避免所有问题:

$a0  = 1;
$a5  = 2;
$a23 = 3;
print scalar(keys %a), "\n";  # prints 3

此解决方案计算零和 undef 值。

【讨论】:

这个答案的最后一部分是正确的。 Grillix 似乎来自 php 背景。 PHP 所说的“数组”实际上更类似于 Perl 的哈希值,在这种情况下应该使用后者。 如何将这个想法扩展到perl中的多维数组? grep 格式的小修复:print scalar(grep $_ @a), "\n"; @arikin:我添加了一个逗号来解决语法问题。感谢您指出!【参考方案2】:

听起来您想要sparse array。一个普通的数组有 24 个元素,而稀疏数组有 3 个元素。在 Perl 中,我们用散列值模拟稀疏数组:

#!/usr/bin/perl

use strict;
use warnings;

my %sparse;

@sparse0, 5, 23 = (1 .. 3);

print "there are ", scalar keys %sparse, " items in the sparse array\n",
    map  "\t$sparse$_\n"  sort  $a <=> $b  keys %sparse;

标量上下文中的keys 函数将返回稀疏数组中的项目数。使用散列来模拟稀疏数组的唯一缺点是,如果键的顺序很重要,则必须在对它们进行迭代之前对其进行排序。

您还必须记住使用delete 函数从稀疏数组中删除项目(仅将它们的值设置为 undef 是不够的)。

【讨论】:

这是正确的。但是,Tie::IxHash 是可选的;在您的示例中,这似乎没有必要。此外,无需提供谓词进行排序,因为这是默认设置。 “排序键 %sparse”也可以。 哎呀,Tie::IxHash 是从另一个示例中遗留下来的。让我删除它。 @Spoulson 否,默认排序是词法而非数字,因此键(1、2 和 10)将被排序(1、10、2)。【参考方案3】:

也许您想要一个哈希来代替(或另外)。数组是一组有序的元素;如果创建$foo[23],则隐式创建$foo[0]$foo[22]

【讨论】:

【参考方案4】:
print scalar grep  defined $_  @a;

【讨论】:

解释:perl 并没有真正的“稀疏”数组,因为 grilix 想要它们。如果你说“我的@a; $a[10]=5;”然后 perl 创建一个包含 11 个条目的数组:前 10 个用“undef”填充,第 11 个用“5”填充。 “scalar @a”和“$#a”报告的总是总长度/最后一个索引。 kcwu 过滤数组以仅计算定义的条目。 可以,但是效果不好。 grep 函数是 O(n),这意味着如果你有 @a[1, 1_000_000] = (1, 2);那么它必须查看 1,000,000 个项目中的每一个来为您计数,这也意味着您将无缘无故地占用大量内存,请改用哈希。 是的。如果我必须使用数组,它可以工作,但我认为我可以使用散列代替。无论如何,他只是回应我的要求。谢谢大家。 你能add an explanation to your answer吗?但是没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的。【参考方案5】:
@people = qw( bob john linda ); 
$n = @people; # The number 3
Print " The number in the list is $n \n"; 

Perl 中的表达式总是为其上下文返回适当的值。

例如,数组的“名称” * 怎么样?在列表上下文中,它给出了元素列表。但在标量上下文中,它返回数组中元素的数量。

【讨论】:

【参考方案6】:
sub uniq 
    return keys % map  $_ => 1  @_ ;

my @my_array = ("a","a","b","b","c");
#print join(" ", @my_array), "\n";
my $a = join(" ", uniq(@my_array));
my @b = split(/ /,$a);
my $count = $#b;

【讨论】:

这段代码有严重的问题。首先是最重要的,如果数组中的项目包含空格,则会被破坏。其次,它对整个数组项集进行一次迭代,对已定义项集进行两次迭代。第三,与所有基于数组的解决方案一样,它无法区分用户设置的 undefs 与数组中的空槽(根据代码的使用方式,这可能还不错)。

以上是关于在 Perl 中计算稀疏数组中的元素的主要内容,如果未能解决你的问题,请参考以下文章

数组和稀疏矩阵

稀疏数组

理解JS里的稀疏数组与密集数组

稀疏数组

多维数组-矩阵的压缩存储- 稀疏矩阵(一)

Fortran:稀疏数组或列表