Простой способ сделать отображение группы элементов последовательного списка

Нормальное сопоставление применяет функцию к элементу списка и создает элемент результирующего списка. Например, если список (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>?

Я могу, конечно, написать процедуру для перемещения по списку. Но я ищу более простой способ, например, оператор сокращения или как сбор/принятие.

Ответ 1

Вы можете использовать метод .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 для применения вашей операции (например, суммы) к каждому подсписку:

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

Функциональный способ программирования заключается в том, чтобы дважды ссылаться на список, смещать одну версию на один элемент и связывать их вместе. Это дает вам все кортежи последующих элементов.

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 };
}

Если вы используете функцию, которая принимает два параметра, вы можете сгладить список после zipping и пусть map будет принимать по два элемента за раз:

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