Каждый раз, когда вы пытаетесь выполнить FP-код, который выполняет итерации по последовательности при обновлении некоторого изменяемого состояния, хорошим первым подходом является использование foldLeft
:
val myInputTable =
Array(Array("Product A","Customer 1"), Array("Product B","Customer 1"),
Array("Product C","Customer 2"), Array("Product A","Customer 2"))
val (products, customers) =
myInputTable.foldLeft((Set.empty[String], Set.empty[String])) {
case ((ps, cs), Array(p, c)) => (ps + p, cs + c)
case ((ps, cs), _) => (ps, cs) // Alternatively fail here.
}
Первый аргумент дляfoldLeft
- начальное состояние.Мы хотим работать с двумя неизменяемыми наборами, поэтому мы используем кортеж Set.empty[String]
.Следующим аргументом foldLeft
здесь является функция:
{
case ((ps, cs), Array(p, c)) => (ps + p, cs + c)
case ((ps, cs), _) => (ps, cs) // Alternatively fail here.
}
Это должна быть функция из текущего накопленного состояния (ps, cs)
и каждого элемента Array(p, c)
до следующего состояния.Он будет применяться к каждой функции в коллекции слева направо (отсюда foldLeft
), накапливая изменения состояния, и будет возвращать окончательное значение состояния.Это работает так:
scala> val (products, customers) =
| myInputTable.foldLeft((Set.empty[String], Set.empty[String])) {
| case ((ps, cs), Array(p, c)) => (ps + p, cs + c)
| case ((ps, cs), _) => (ps, cs) // Alternatively fail here.
| }
products: scala.collection.immutable.Set[String] = Set(Product A, Product B, Product C)
customers: scala.collection.immutable.Set[String] = Set(Customer 1, Customer 2)
В некоторых случаях могут быть более конкретные комбинаторы, которые позволяют вам выразить вашу работу более кратко, но foldLeft
является хорошей общей отправной точкой, которая позволяет довольно простые переводы с изменяемогов чисто функциональный код.