Perl排序数组时引用元素导致生成新元素的问题咨询
Perl中引用数组元素导致sort后元素地址变化的原因
核心原因:Perl的sort优化与引用的内存锁定
当你不对数组元素创建任何外部引用时,Perl的sort会采用原地排序优化:直接在原数组的内存空间中调整元素的位置,不会创建新的标量。这就是注释掉引用代码后,排序前后数组元素内存地址完全一致的原因——只是数组索引指向的原有标量位置发生了交换。
但当你通过push @order, \$_将数组元素的引用保存到另一个数组后,这些引用会锁定原数组元素的内存位置:Perl的内存管理系统知道这些元素仍被外部引用,无法被移动或覆盖。此时sort无法进行原地排序,只能创建新的标量,将排序后的字符串值复制到新标量中,再将这些新标量的地址存入原数组。这就导致排序后的数组元素是全新的标量,内存地址自然和原元素不同。
验证与解决思路
如果你需要保留原数组元素的引用,同时得到排序后的结果,可以选择以下两种方式:
- 复制数组后排序:不对原数组执行
sort,而是创建一个副本进行排序,原数组的元素地址不会改变:my @item = qw/zz xx/; my @order = map { \$_ } @item; # 打印原元素信息 print $item[0] . " " . \$item[0] . "\n"; print $item[1] . " " . \$item[1] . "\n"; # 对副本排序,原数组不受影响 my @sorted_item = sort {$a cmp $b} @item; # 打印排序后的副本信息 print $sorted_item[0] . " " . \$sorted_item[0] . "\n"; print $sorted_item[1] . " " . \$sorted_item[1] . "\n"; - 排序索引而非元素:如果需要对原数组排序但保留元素引用,可以通过排序索引的方式重新排列原数组,元素本身的内存地址不会改变:
my @item = qw/zz xx/; my @order = map { \$_ } @item; # 打印原元素信息 print $item[0] . " " . \$item[0] . "\n"; print $item[1] . " " . \$item[1] . "\n"; # 排序索引,再重新排列原数组 @item = @item[ sort { $item[$a] cmp $item[$b] } 0..$#item ]; # 打印排序后的原数组元素信息,地址与原元素一致 print $item[0] . " " . \$item[0] . "\n"; print $item[1] . " " . \$item[1] . "\n";
内容的提问来源于stack exchange,提问作者Mr. Noob
相关产品推荐
相关产品推荐

