Мне действительно нравятся концепции функционального программирования, но теперь я был укушен в двух разных случаях одной и той же ошибкой, когда отображал коллекцию, которая оказывается Set
(т.е. автоматически удаляет дубликаты). Проблема заключается в том, что после преобразования элементов такого набора выходной контейнер также является набором и поэтому удаляет все дубликаты вывода , преобразованного .
Очень короткая сессия REPL, чтобы проиллюстрировать проблему:
scala> case class Person(name: String, age: Int)
defined class Person
scala> val students = Set(Person("Alice", 18), Person("Bob", 18), Person("Charles", 19))
students: scala.collection.immutable.Set[Person] = Set(Person(Alice,18), Person(Bob,18), Person(Charles,19))
scala> val totalAge = (students map (_.age)).sum
totalAge: Int = 37
Я бы, конечно, ожидал, что общий возраст будет 18 + 18 + 19 = 55, но поскольку учеников были сохранены в Set
, то же самое было и в их возрасте после отображение, следовательно, один из 18
исчез, прежде чем были суммированы возрасты.
В реальном коде это часто бывает более коварным и труднее обнаружить, особенно если вы пишете служебный код, который просто принимает Traversable
и / или использует вывод методов, которые объявлены для возврата Traversable
(реализация который случается быть сетом). Мне кажется, что эти ситуации почти невозможно надежно определить до тех пор, пока они не проявятся как ошибка.
Итак, , есть ли лучшие практики, которые уменьшат мою подверженность этой проблеме ? Неправильно ли я думать о map
-произведении общего Traversable как о концептуальном преобразовании каждого элемента на месте, а не о добавлении преобразованных элементов в свою очередь в какую-то новую коллекцию? Должен ли я позвонить .toStream
на все перед картированием, если я хочу сохранить эту ментальную модель?
Любые советы / рекомендации будут с благодарностью.
Обновление : Большинство ответов до сих пор были сосредоточены на механике включения дубликатов в сумму. Меня больше интересуют практики, связанные с написанием кода в общем случае - вы тренировали себя до всегда , звоните toList
в каждой коллекции, прежде чем вызывать map
? Пристально ли вы проверяете конкретные классы всех коллекций в вашем приложении, прежде чем вызывать на них методы? И т.д.
Исправление чего-то, что уже было определено как проблема, является тривиальным - сложная часть предотвращает появление этих ошибок в первую очередь.