#scala
#scala
Вопрос:
Мне часто нужно суммировать преобразование списка чисел в Scala. Один из способов сделать это, конечно,:
list.map(transform(_)).sum
Однако это создает память, когда создание памяти не требуется. Альтернативой является свертывание списка.
list.foldLeft(0.0) { (total, x) => total f(x) }
Я нахожу, что первое выражение гораздо проще написать, чем второе выражение. Есть ли метод, который я могу использовать, который отличается простотой первого и эффективностью второго? Или мне лучше написать свой собственный неявный метод?
list.mapSum(transform(_))
Комментарии:
1. Связано только по касательной, но будьте осторожны, если суммирование преобразований по множествам , например:
Set(1,2,3).map(_ % 2).sum
является1
, не2
. Недавно меня укусило что-то вродеsetOfPlayers.map(_.salary).sum
…
Ответ №1:
Вы можете использовать представление, чтобы сделать ваши методы преобразования (map, filter …) ленивыми. Смотрите здесь для получения дополнительной информации.
Так, например, в вашем случае с методом, вызываемым transform
, вы бы написали
list.view.map(transform).sum
(обратите внимание, что вы можете опустить (_)
)
Комментарии:
1. Я помнил об этом, но какое-то ошибочное тестирование убедило меня, что это замедляет работу. Сегодня, после еще нескольких попыток,
view
кажется отличным!2. @schmmd в некоторых тривиальных случаях реализация
view
замедлит работу, что может быть причиной того, что она не применяется автоматически по умолчанию. Я думаю, что это зависит от таких факторов, как доля элементов, которые вы используете / отфильтровываете. Также скорость != память. Поэтому, вероятно, лучше всего попробовать это и сравнить, если скорость имеет решающее значение.3. В этом примере я должен просто использовать итератор.
4. @schmmd Это, безусловно, вариант, при котором вам нужно иметь дело только со всем списком или с первыми n элементами. Представления более гибкие, поскольку вы можете обращаться к элементам случайным образом столько раз, сколько захотите. Итераторы происходят из императивного программирования и имеют изменяемое состояние, поэтому их обычно лучше избегать в функциональном коде.
5. Хорошо понятно, но представления в scala считаются чрезвычайно проблематичными до такой степени, что многие люди хотят их удалить, поэтому я их избегаю.
Ответ №2:
Эта операция называется foldMap
, и вы можете найти ее в Scalaz.
list foldMap transform
Комментарии:
1. 1 когда я начну использовать scalaz, моя будущая замена действительно возненавидит меня.
2. Как указано, это выражение не суммирует элементы, не так ли?
3. Для дальнейшей разработки,
foldMap
имеет следующую сигнатуру типа:def foldMap[A, M: Monoid](t: F[A], f: A => M): M
, поэтому ваше преобразование должно возвращать что-то, что является моноидом, и, следовательно, имеет «ноль» и| |
операцию, котораяfoldMap
будет использоваться для накопления результата.4. @Zwirb в этой подписи есть два параметра, но я вижу только один аргумент в ответе. Что такое
F[A]
?5. @LuigiPlinge: вы правы! Я процитировал метод def из
Foldable
признака вместо метода изMA
признака, который фактически используется здесь (и в конечном итоге вызывает метод вFoldable
):def foldMap[B](f: A => B)(implicit r: Foldable[M], m: Monoid[B]): B = r.foldMap(value, f)
, гдеvalue
ваш исходный список, который был преобразован во что-то сMA
признаком. Это также сбивает меня с толку, кстати: Я едва начинаю ориентироваться в scalaz…