列表和数组有什么区别?

12
这个页面上, 展示了如何初始化一个数组。如果您向下滑动一点,在名为“列表”的部分下面,它会“解释”什么是列表以及它们与数组的区别。

但它使用的例子与声明数组完全相同,根本没有解释。

两者有什么区别?


你的参考资料有误导性。它说数组只是一组标量,然而实际上它远不止于此。 - Borodin
还有比这更少,因为#!math {2, 3, 2}不是一个集合。 - darch
@darch:我认为这里数学中的“集合”概念是不相关的。 - Borodin
3
我认为你提到的那个页面相当令人困惑。在我看来,“列表实际上是一种特殊类型的数组”是无稽之谈。Perl有三种类型的变量:标量、数组和哈希。列表只是它们字面意义上的意思:标量的一个列表。就像你有一个购物清单,它是你需要购买的物品的一个列表。没有必要把事情弄复杂。 - TLP
8个回答

10

请查看perldoc -q "列表和数组"。最大的区别是数组是一个变量,但是Perl的所有数据类型(标量、数组和哈希)都可以提供列表,它只是一组有序的标量。

考虑以下代码

use strict;
use warnings;

my $scalar = 'text';
my @array = (1, 2, 3);
my %hash = (key1 => 'val1', key2 => 'val2');

test();
test($scalar);
test(@array);
test(%hash);

sub test { printf "( %s )\n", join ', ', @_ }
这将输出以下内容
(  )
( text )
( 1, 2, 3 )
( key2, val2, key1, val1 )
Perl子例程以一个列表作为其参数。第一种情况下,列表为空;第二种情况下,它有单个元素($scalar);第三种情况下,列表与@array的大小相同,并包含($array [0],$array [1],$array [2],...),最后一种情况下,它是哈希%hash中元素数量的两倍,并且包含('key1',$hash {key1},'key2',$hash {key2},...)。
显然,该列表可以通过多种方式提供,包括标量变量、标量常量和子例程调用的结果,例如:
test($scalar, $array[1], $hash{key2}, 99, {aa => 1, bb => 2}, \*STDOUT, test2())

我希望你能明白,这样的列表和数组是非常不同的。

把数组看作是列表变量,这样有帮助吗?通常很容易区分标量字面量和标量变量。例如:

my $str = 'string';
my $num = 99;

很明显,'string'99是字面值,而$str$num是变量。在这里的区别也是一样的:

my @numbers = (1, 2, 3, 4);
my @strings = qw/ aa bb cc dd /;

(1, 2, 3, 4)qw/ aa bb cc dd /是列表字面量,而@numbers@strings是变量。


5
哦天啊,它的尺寸变成了两倍大! - temporary_user_name

8

实际上,这个问题在Perl常见问题解答中已经有很好的回答。列表是组织Perl源代码数据的方法之一。数组是存储数据的一种类型,哈希是另一种。

它们的区别非常明显:

my @arr = (4, 3, 2, 1);
my $arr_count  = @arr;
my $list_count = (4, 3, 2, 1);

print $arr_count, "\n"; # 4
print $list_count;      # 1

乍一看,这里有两个完全相同的列表。但请注意,只有分配给@arr变量的那个才能正确计算标量赋值的结果。$list_count存储1-使用逗号运算符计算表达式的结果(基本上给我们枚举中的最后一个表达式-1)。
请注意,列表运算符/函数和数组运算符/函数之间存在轻微但非常重要的差异:前者是一种类似万能的东西,因为它们不会改变源数据,而后者则不然。例如,您可以安全地对列表进行切片和连接,如下所示:
print join ':', (4,2,3,1)[1,2]; 

但是尝试“弹出”它会给你一个相当明显的消息:

pop (4, 3, 2, 1);
### Type of arg 1 to pop must be array (not list)...

5
不,它们显然不是同一件事。列表和数组的行为可以非常不同(如上所述),了解差异对于编写没有漏洞的Perl至关重要。 - darch
3
谈论列表计数是无意义和误导的。我不赞成。 - ikegami
2
你最后的例子有严重的缺陷。将4更改为$x,则不会出现错误(在5.16中)。你的例子并没有展示你所声称的内容。 - ikegami
1
@Aerovistae,不,数组是保存标量值的变量。您可以通过将列表分配给它来为数组分配值,但它们不保存列表。列表和数组远非相似,与“同一件事”相去甚远。 - ikegami
3
数组和列表与标量变量、字符串或数字一样,不是“同一回事”。 - Borodin
显示剩余3条评论

8

数组是一种变量类型。它包含0个或多个标量,这些标量的索引单调递增。例如,以下代码创建了一个名为@a的数组:

my @a;

作为变量,您可以操作数组。您可以添加元素,更改元素的值等。
“列表”有很多含义。它的两个主要用途是指代列表值和列表运算符的实例。
列表值是堆栈上零个或多个标量的有序集合。例如,以下代码中的子程序返回一个列表,以分配给@a(一个数组)。
my @a = f();

列表值无法被操作; 它们被传递给任何运算符时整个地吸收。它们只是在子程序和运算符之间传递值的方式。


列表运算符(,)是一个N元运算符*,按顺序评估它的每个操作数。在列表上下文中,列表运算符返回一个列表,包含其操作数返回的列表的合并。例如,以下代码片段中的列表运算符返回一个列表值,其中包含数组@a@b的所有元素:

my @c = ( @a, @b );

顺便提一下,括号并不创建列表。它们只是为了覆盖优先级。

由于其是代码,因此您无法操作列表运算符。


* ——文档中说它是二进制运算符(至少在标量上下文中),但这是不正确的。


什么是列表运算符?逗号吗?逗号在数组和哈希中也存在,对吗? - temporary_user_name
@Aerovistae,关于“什么是列表运算符?”的问题,另一个名称是逗号运算符。/// 关于“数组和哈希表中不也有逗号吗?”的问题,什么? - ikegami
哈希和数组都可以包含逗号:(1, 2)("key" => "value", "key2" => "value2")。我不确定我的观点是什么了。叹气。Perl 是不同的。 - temporary_user_name
@Aerovistae,那些不是数组或哈希表;它们都是逗号运算符的实例(根据上下文返回最后一个值或所有值)。数组和哈希表是变量类型,而那些不是变量。 - ikegami
所以,如果我的理解是正确的,@a = (1,2,7); $b = @a; 将导致 $b3(数组的长度),而 $b = (1, 2, 7) 将导致 $b7,因为逗号运算符只返回列表中的最后一个值,因为它是标量上下文。对吗? - temporary_user_name
显示剩余3条评论

3

差异的简单演示。

sub getarray{ my @x = (2,4,6); return @x; }

sub getlist { return (2,4,6); }

现在,如果你像这样做:

现在,如果您执行以下操作:

 my @a = getarray();
 my @b = getlist();

然后,@a@b 都将包含相同的值 - 列表 (2,4,6)。但是,如果你这样做:

my $a = getarray();
my $b = getlist();

那么,$a将包含值3,而$b将包含值6。

因此,可以说数组是包含列表值的变量,但这并不能说明整个故事,因为数组和文字列表在某些情况下表现得完全不同。


3

列表是逗号分隔值(CSV)或表达式(CSE)。数组(和哈希)是容器。

可以通过列表来初始化数组或哈希:

@a = ("profession", "driver", "salary", "2000");
%h = ("profession", "driver", "salary", "2000");

可以返回一个列表:

sub f {
    return "moscow", "tel-aviv", "madrid";
}

($t1, $t2, $t3) = f();
print "$t1 $t2 $t3\n";

($t1, $t2, $t3) 是一个标量容器列表,分别代表 $t1、$t2、$t3。

列表是 Perl 表达式的一种形式(语法的一部分),而数组则是数据结构(内存位置)。


2
列表和数组的区别让很多人感到困惑。Perl本身通过错误地命名其内置函数wantarray()而搞错了:“这个函数应该被命名为wantlist()。”在perlfaq4中有一个答案"What is the difference between a list and an array?",但它并没有解决我的困惑。
我现在相信以下内容是正确的:
  • 在标量上下文中,数组变成了它的元素个数。
  • 在标量上下文中,逗号操作符返回最后一个元素。
  • 你不能创建一个列表的引用;\(2, 4, 6)返回一个对列表中标量的引用的列表。你可以使用[2, 4, 6]来创建一个匿名数组的引用。
  • 如果你制作一个列表切片,你可以索引一个列表(获取它的第n个元素),而不必创建一个数组,因此(2, 4, 6)[1]是4。

但是如果我想要计算列表中的元素数量或获取数组的最后一个元素怎么办?我需要在数组和列表之间进行转换吗?

你总是可以使用[...]语法将列表转换为数组。计算列表中元素的数量的一种方法是创建一个匿名数组,然后立即在标量上下文中取消引用它,如下所示:

sub list { return qw(carrot stick); }
my $count = @{[list()]};
print "Count: $count\n";  # Count: 2

另一种方法是使用列表赋值运算符,如下所示:
sub list { return qw(carrot stick); }
my $count = (()=list());
print "Count: $count\n";  # Count: 2

这段代码中没有数组,但列表赋值操作符返回被赋值的元素个数。 我将它们赋值给一个空变量列表。 在代码高尔夫中,我使用()=$str=~/reg/g 来计算某个字符串中正则表达式匹配的次数。
你无需将数组转换为列表,因为在列表上下文中的数组已经是一个列表。如果你想要获取数组的最后一个元素,只需使用$array[-1]
逗号操作符会返回列表的最后一个元素,但我无法用它来获取数组的最后一个元素。如果我在标量上下文中说((),@array),那么@array就处于标量上下文中,我就可以获取元素的个数。
您不需要创建一个数组来索引一个列表。您可以创建一个匿名数组,例如[list()]->[1],或者您可以创建一个列表切片,例如(list())[1]。我在处理列表切片时遇到了麻烦,因为它们有不同的语法。列表切片需要括号!在C、Python或Ruby中,func()[1]会对函数返回值进行数组索引,但在Perl中,func()[1]是语法错误。您必须这样写:(func())[1]
例如,我想打印数组中第三大的数字。因为我很懒,所以我排序了数组并取了倒数第三个元素:
my @array = (112, 101, 114, 108, 32, 104, 97, 99, 107);
print +(sort { $a <=> $b } @array)[-3], "\n";  # prints 108

一元运算符+可以防止print()函数窃取我的括号。

您可以在数组上使用列表切片,例如(@array)[1]。这是因为数组也是一个列表。列表和数组的区别在于,数组可以执行$array[1]操作。


0

数组 Vs 列表

列表是一种不同于数组的数据结构。

最大的区别在于直接访问 Vs 顺序访问的理念。数组允许直接和顺序访问,而列表只允许顺序访问。这是因为这些数据结构在内存中的存储方式不同。

此外,列表的结构不支持像数组那样的数字索引。元素也不需要像数组那样在内存中相邻地分配。

数组

数组是一个有序的项集合,其中每个项都有一个索引。


在 Perl 上下文中讨论的事情中,调用列表中最不可能被讨论的是链表。 - ikegami

-2

这里是我关于符号和上下文的答案

但主要区别在于:

数组有一个类似于元素数量标量上下文值

列表有一个类似于列表中的最后一个元素标量上下文值

所以,你需要了解goat-operator=()=

用法?

perl -e '$s =()= qw(a b c); print $s' # uh? 3? (3 elements, array context)

perl -e '$s = qw(a b cLastElementThatYouSee); print $s' # uh? cLastElementThatYouSee? (list context, last element returned)

正如您所看到的,=()= 将上下文更改为 array


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接