我正在尝试根据每个字符串的第一部分(即,如果有选项卡,则在第一个选项卡之前的部分或如果没有选项卡的整个字符串)对字符串列表中的多个项目进行分组.
这有效:
use Test; my @lines = "A\tFoo","A\tBar","B","A\tBaz","B" ; my @expected = ["A\tFoo","A\tBar"],["B","B"],["A\tBaz"],["B"] ; my @result = group-lines(@lines); is @result,@expected,"Grouped correctly"; sub group-lines (@records) { my @groups; my @current-records; my $last-type; for @records -> $record { my $type = $record.split("\t")[0]; once { $last-type = $type } if $type ne $last-type { @groups.push: [@current-records]; @current-records = (); } @current-records.push: $record; LAST { @groups.push: [@current-records] } } return @groups; }
但它似乎很冗长.在Perl 6中没有更短的方法吗?请注意,我只想将类似于原始列表的连续成员的项目分组.
(更新)组内的顺序很重要.
UPDATE
这是一个更加数字化的例子.它根据后续数字与第一个数字的可分性对数字进行分组.
#!/bin/env perl6 use Test; my @numbers = 2,4,6,3,9,12,14; my @expected = [2,6],[3,12],[14]; my @result = group-nums(@numbers); is @result,"Grouped correctly"; sub group-nums (@numbers) { my @groups; my @current-group; my $denominator = @numbers[0]; for @numbers -> $num { if $num % $denominator { @groups.push: [@current-group]; @current-group = (); } @current-group.push: $num; } @groups.push: [@current-group]; return @groups; }
解决方法
这是一个功能灵感的解决方案,虽然可能有点复杂:
use Test; my @lines = "A\tFoo",["B"] ; my @eq = @lines.map(*.split("\t")[0]).rotor(2 => -1).map({ [eq] .list}); my @result = [@lines[0],],; for @lines[1..*] Z @eq -> ($line,$eq) { @result.push([]) unless $eq; @result[*-1].push: $line; } plan 1; is-deeply @result,@expected;
这个想法是@eq包含每个位置(第一个除外)如果前一个元素与当前元素具有相同的前缀,则为真.
但是我们并没有假装Lisp是唯一真神,而car和cdr是她的先知,我们可以简单地通过使用数组索引在我们需要时访问前一个元素来内联该决定:
my @result; for @lines.kv -> $idx,$elem { @result.push([]) if $idx == 0 || $elem.split("\t")[0] ne @lines[$idx-1].split("\t")[0]; @result[*-1].push: $elem; } plan 1; is-deeply @result,@expected;