Perl 6在循环遍历列表时显示索引

Eug*_*sky 4 perl6 raku

循环遍历列表(或数组)时,有没有办法知道循环中当前元素的索引?

当然,问题可以通过索引循环来解决:

my @aa = 8 .. 12;
say "$_\t@aa[$_]" for 0 ..^ @aa.elems;
Run Code Online (Sandbox Code Playgroud)

但也许类似下面的内容是可能的(我用.CURRENT_INDEX我正在寻找的方法标记)?

my @aa = 8 .. 12;
say $_.CURRENT_INDEX\t$_ for @aa;
Run Code Online (Sandbox Code Playgroud)

Håk*_*and 5

要在列表中获取循环的当前元素的循环索引,可以使用.kv列表的方法.它返回一个交错的索引和值序列:

my @aa = 8 .. 12;
for @aa.kv -> $i, $_ { say "$i: $_" }
Run Code Online (Sandbox Code Playgroud)

输出:

0: 8
1: 9
2: 10
3: 11
4: 12
Run Code Online (Sandbox Code Playgroud)


Bra*_*ert 4

TLDR:使用.kv.pairs


这就是幕后真正发生的事情:

my @aa = 8 .. 12;

my \iterator = @aa.iterator;

while ($_ := iterator.pull-one) !=:= IterationEnd {
  say $_
}
Run Code Online (Sandbox Code Playgroud)

本例中的值iterator是一个匿名类,它执行Iterator角色的匿名类。

迭代可能有也可能没有任何方法知道它产生了多少个值。例如,迭代器for.roll(*)不需要知道到目前为止它已经生成了多少个值,因此它不需要知道。


迭代器可以实现返回其当前索引的方法。

my @aa = 8 .. 12;

my \iterator = class :: does Iterator {
  has $.index = 0;     # declares it as public (creates a method)
  has @.values;

  method pull-one () {
    return IterationEnd unless @!values;

    ++$!index;         # this is not needed in most uses of an Iterator
    shift @!values;
  }
}.new( values => @aa );

say "{iterator.index}\t$_" for Seq.new: iterator;
Run Code Online (Sandbox Code Playgroud)
1   8
2   9
3   10
4   11
5   12
Run Code Online (Sandbox Code Playgroud)

您也可以在更高级别的构造中执行此操作;

my @aa = 8 .. 12;

my $index = 0;
my $seq := gather for @aa { ++$index; take $_ };

say "$index\t$_" for $seq;
Run Code Online (Sandbox Code Playgroud)

要开始$_.CURRENT-INDEX工作,需要包装结果。

class Iterator-Indexer does Iterator {
  has Iterator $.iterator is required;
  has $!index = 0;

  method pull-one () {
    my \current-value = $!iterator.pull-one;

    # make sure it ends properly
    return IterationEnd if current-value =:= IterationEnd;

    # element wrapper class
    class :: {
      has $.CURRENT-INDEX;
      has $.value;

      # should have a lot more coercion methods to work properly
      method Str () { $!value }

    }.new( CURRENT-INDEX => $!index++, value => current-value )
  }
}

multi sub with-index ( Iterator \iter ){
  Seq.new: Iterator-Indexer.new: iterator => iter;
}
multi sub with-index ( Iterable \iter ){
  Seq.new: Iterator-Indexer.new: iterator => iter.iterator;
}


my @aa = 8 .. 12;
say "$_.CURRENT-INDEX()\t$_" for with-index @aa.iterator;
# note that $_ is an instance of the anonymous wrapper class
Run Code Online (Sandbox Code Playgroud)

再次使用更高级别的构造:

my @aa = 8 .. 12;

my \sequence := @aa.kv.map: -> $index, $_ {
  # note that this doesn't close over the current value in $index
  $_ but role { method CURRENT-INDEX () { $index }}
}

say "$_.CURRENT-INDEX()\t$_" for sequence;
Run Code Online (Sandbox Code Playgroud)

我认为.pairs如果你想要这样的东西,你应该使用它。(或使用.kv,但基本上需要使用for带有两个参数的块形式)

my @aa = 8 .. 12;
say "$_.key()\t$_.value()" for @aa.pairs;
Run Code Online (Sandbox Code Playgroud)