Простой способ сделать отображение группы элементов последовательного списка
Нормальное сопоставление применяет функцию к элементу списка и создает элемент результирующего списка. Например, если список (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:<+>);
}