代码之家  ›  专栏  ›  技术社区  ›  lisprogtor

一种简单的顺序列表元素组映射方法

  •  10
  • lisprogtor  · 技术社区  · 7 年前

    法线映射将函数应用于列表元素并生成结果列表的元素。E、 g.,如果列表为 (1, 2, 3,) 然后映射平方函数,得到一个新列表 (1, 4, 9,) .

    有没有办法映射列表中的一组连续元素?例如,如果列表为 <8 2 7 2 6 9 4 9 6 1> 我想计算列表中每两个元素的总和 <10 9 9 8 15 13 13 15 7> ?

    我当然可以编写一个例程来遍历列表。但我正在寻找一种更简单的方法,比如reduction操作符或gather/take。

    2 回复  |  直到 6 年前
        1
  •  11
  •   smls    7 年前

    您可以使用 .rotor 将列表划分为重叠子列表的方法:

    say <8 2 7 2 6 9 4 9 6 1>.rotor(2 => -1);
    
    # Output:
    # ((8 2) (2 7) (7 2) (2 6) (6 9) (9 4) (4 9) (9 6) (6 1))
    

    这个 2 => -1 是一个 Pair 参数,该参数向方法指示它应该在每一步“向前两步,向后一步”生成子列表。

    然后你可以简单地使用 .map 要将操作(如sum)应用于每个子列表,请执行以下操作:

    say <8 2 7 2 6 9 4 9 6 1>.rotor(2 => -1).map(*.sum);
    
    # Output:
    # (10 9 9 8 15 13 13 15 7)
    
        2
  •  6
  •   piojo    7 年前

    实现这一点的函数式编程方法是引用列表两次,用一个元素偏移一个版本,然后将它们压缩在一起。这将为您提供后续元素的所有元组。

    my @l := <a b c d e f>;
    say @l Z @l[1..*]; # output: ((a b) (b c) (c d) (d e) (e f))
    

    如果不想创建临时变量来保存列表,请使用 given (和使用 do given 如果需要语句返回值):

    given <8 2 7 2 6 9 4 9 6 1> {
      say ($_ Z $_[1..*]).map: -> [$a, $b] { $a+$b };
    }
    

    如果您使用的函数具有两个参数,那么您可能希望在压缩后将列表展平,并让 map 一次取两个元素:

    given <8 2 7 2 6 9 4 9 6 1> {
      say ($_ Z $_[1..*]).flat.map(&infix:<+>);
    }