在 Scala 中以函数方式迭代表填充 2 个 HasSet

Pho*_*oen 5 functional-programming scala

我正在编写一个 Scala 应用程序,并试图以一种功能方式遍历一个表(以二维数组的形式)。对于表中的每一行,我想用第一列中的所有不同值填充一个集合,并用第二列中的所有不同值填充第二个集合。

我尝试了很多方法,但找不到任何解决方案如何以功能风格来做到这一点。因为我从迭代中获得了 2 个新变量,如果没有非功能性帮助,这似乎是不可能的。

这是一个非功能性示例,其中包含用于包含产品和客户的表的可变 HashSet:

val myInputTable =
  Array(Array("Product A","Customer 1"), Array("Product B","Customer 1"),
    Array("Product C","Customer 2"), Array("Product A","Customer 2"))

val productSet = new collection.mutable.HashSet[String]
val customerSet = new collection.mutable.HashSet[String]

for(
  inputLine <- myInputTable;
  inputElement <- inputLine
) {
  if (inputLine.indexOf(inputElement) == 0) {
    productSet.add(inputElement)
  } else {
    customerSet.add(inputElement)
  }
}

println("Product Set:")
productSet.foreach(println)
println("\nCustomer Set:")
customerSet.foreach(println) 
Run Code Online (Sandbox Code Playgroud)

有没有办法用不可变的集合、其他对象或者 for-yield 语法来做到这一点?

感谢您的任何答案或提示,

菲利克斯

Tra*_*own 4

每当您发现自己尝试对某些在更新某些可变状态时迭代序列的代码进行 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.
  }
Run Code Online (Sandbox Code Playgroud)

第一个参数foldLeft是初始状态。我们想要使用两个不可变的集合,因此我们使用 的元组Set.empty[String]。这里的下一个参数foldLeft是一个函数:

  {
    case ((ps, cs), Array(p, c)) => (ps + p, cs + c)
    case ((ps, cs), _) => (ps, cs) // Alternatively fail here.
  }
Run Code Online (Sandbox Code Playgroud)

(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)
Run Code Online (Sandbox Code Playgroud)

在某些情况下,可能有更具体的组合器,可以让您更简洁地表达您的操作,但它foldLeft是一个很好的通用起点,允许从可变代码到纯函数代码的相当简单的转换。