我试图将数值数组拆分成更小的数组,这样每个较小的数组都不能包含任何不同的数字。
示例:数组(2,2,2,2,2,9,3,3,3,3)
应分为三个数组(2,2,2,2,2)
,(9)
和(3,3,3,3)
。
以下是我的尝试:
my @arr = (2,2,2,2,2,9,3,3,3,3);
my @result = ();
my $last = -1;
my @newarr = ();
for my $i (0 .. $#arr){
if ( ($i>0 && $arr[$i] != $last) || $i == $#arr ){
push @result, \@newarr;
@newarr = ();
}
$last = $arr[$i];
push @newarr, $arr[$i];
}
首先,这段代码没有给我想要的结果。我认为我的错误是当我将@newarr
的引用推送到@result
时,然后我重新初始化@newarr
。
其次,还有更优雅的方法吗?我查看了函数split
和splice
,但想不到一个好的解决方案。
答案 0 :(得分:5)
List :: MoreUtils具有“part
”功能:
use Data::Dumper;
use feature 'state';
use List::MoreUtils 'part';
my @array = ( 2,2,2,2,2, 9, 3,3,3,3 );
my @part = part {
state $prev;
state $i = -1;
$i++ if !defined($prev) || $_ ne $prev;
$prev = $_;
$i
} @array;
print Dumper @part;
使用'part',代码块返回的值指示顶级数组索引,其中当前值将被推送到匿名数组中。 $prev
开始是未定义的,因此输入中的第一个元素会触发$i
增加到0
,因此所有'2'都会以@{$part[0]}
结尾。只要@array中的元素与$ prev不匹配,索引就会递增,后续元素会以@{$part[1]}
结尾。每次检测到更改时,都会开始新的分组。
<强>更新强>
如果这段代码可能被多次使用,那么“状态”变量将在调用之间保持其值。在这种情况下,状态比它的价值更麻烦,人们应该在子例程中使用词法:
use Data::Dumper;
use List::MoreUtils 'part';
my @array = ( 2,2,2,2,2, 9, 3,3,3,3 );
my @part = partition(@array);
print Dumper \@part;
sub partition {
my( $prev, $i ) = ( undef, -1 );
return part {
$i++ if ! defined($prev) || $_ ne $prev;
$prev = $_;
$i;
} @_;
}
答案 1 :(得分:3)
创建按相似元素分组的数组数组。
要复习复杂的数据结构,请查看perldsc
。
use strict;
use warnings;
my @array = (2,2,2,2,2,9,3,3,3,3);
my @grouped;
for (@array) {
if (! @grouped || $grouped[-1][0] != $_) {
push @grouped, [];
}
push @{$grouped[-1]}, $_;
}
use Data::Dump;
dd @grouped;
输出:
([2, 2, 2, 2, 2], [9], [3, 3, 3, 3])
答案 2 :(得分:3)
use List::Util 'reduce';
my @arr = (2,2,2,2,2,9,3,3,3,3);
my $result = reduce {
if ( @$a && $b == $a->[-1][0] ) {
push @{ $a->[-1] }, $b
}
else {
push @$a, [ $b ]
}
$a
} [], @arr;
更简单但可能更容易阅读:
my $result = reduce {
push @{ $a->[ @$a && $b == $a->[-1][0] ? -1 : @$a ] }, $b;
$a
} [], @arr;
答案 3 :(得分:2)
my @arr = (2,2,2,2,2,9,3,3,3,3);
my %h;
my @newarr = map {
my $ok = !$h{$_};
push @{$h{$_}}, $_;
$ok ? $h{$_} : ();
}
@arr;
use Data::Dumper; print Dumper \@newarr;
或
my @arr = (2,2,2,2,2,9,3,3,3,3);
my %h;
my @newarr;
for my $v (@arr) {
if (!$h{$v}) {
push @newarr, ($h{$v} = []);
}
push @{$h{$v}}, $v;
}
输出
$VAR1 = [
[
2,
2,
2,
2,
2
],
[
9
],
[
3,
3,
3,
3
]
];
答案 4 :(得分:2)
这将按照你的要求行事。它的工作原理是将数据内容打包为一组数字和计数,然后以所需格式解压缩。输出数据位于@num
。我只使用Data::Dump
来显示结果数据结构。
use strict;
use warnings;
my @arr = (2,2,2,2,2,9,3,3,3,3);
my (%rep, @num);
$rep{$_}++ or push @num, $_ for @arr;
@num = map [ ($_) x $rep{$_} ], @num;
use Data::Dump;
dd \@num;
<强>输出强>
[[2, 2, 2, 2, 2], [9], [3, 3, 3, 3]]
<强>更新强>
上述解决方案将具有相同值的所有元素收集到一个组中,即使它们来自不同的序列。如果您需要在每次更改值时拆分输出数组,那么这将满足您的需要。
use strict;
use warnings;
my @arr = (2,2,2,2,2,9,9,9,2,2,2,9,9,9);
my @groups;
for (@arr) {
push @groups, [ ] unless @groups and $_ == $groups[-1][-1];
push @{ $groups[-1] }, $_;
}
use Data::Dump;
dd \@groups;
<强>输出强>
[[2, 2, 2, 2, 2], [9, 9, 9], [2, 2, 2], [9, 9, 9]]
更新2
根据您对ikegami
评论的回答,这是另一个版本,该评论显示值列表及其相关计数可能更接近您的需求。
use strict;
use warnings;
my @arr = (2,2,2,2,2,9,9,9,2,2,2,9,9,9);
my @groups;
for (@arr) {
if (@groups and $_ == $groups[-1][0]) {
$groups[-1][1] += 1;
}
else {
push @groups, [ $_, 1 ];
}
}
use Data::Dump;
dd \@groups;
<强>输出强>
[[2, 5], [9, 3], [2, 3], [9, 3]]
答案 5 :(得分:2)
强制性正则表达式回答:
my @result = map [ (ord) x length ], grep --$|, join( '', map chr, @arr ) =~ /((.)\2*)/sg;
(在no warnings "non_unicode";
下)。
答案 6 :(得分:1)
您可以创建一个数组哈希,其中has的键将是一个数字。并且每次遇到该数字时,您都可以将其推送到散列的数组引用。因此,所有数字将按预期分成数组。然后,您可以遍历哈希来打印数组或按数字访问每个数组。
use strict;
use Data::Dumper;
my @arr = (2,2,2,2,2,9,3,3,3,3);
my %hash;
push(@{$hash{$_}},$_) foreach (@arr);
print Dumper(\%hash);
输出
$VAR1 = {
'3' => [
3,
3,
3,
3
],
'9' => [
9
],
'2' => [
2,
2,
2,
2,
2
]
};