高效优雅地从案例类结构的List中删除元素

Vik*_*dya 8 scala lenses monocle-scala

我有一个嵌套的case类结构List

为简单起见,请使用以下示例 -

case class Address(street: String, city: String, state: String, zipCode: Int)
case class Person(firstName: String, lastName: String, addresses: List[Address])
case class Department(people: List[Person])
Run Code Online (Sandbox Code Playgroud)

说有List[Department]; 现在,如果我想List[Department]通过过滤Address每个Person没有特定zipCode值的新东西来创建一个新的; 传统上我们可以做到以下

def filterPersonsByAddress(dlist: List[Department]): List[Department] = {
  dlist.map { d =>
    val people = d.people.map { p => 
      p.copy(addresses = p.addresses.filterNot(_.zipCode == 38978))}
      d.copy(people=people)
    }
 }
Run Code Online (Sandbox Code Playgroud)

这种方法不具备性能,因为取决于嵌套级别,它可以是Big O(n ^ 2)或Big O(n ^ 3);

我试图通过Monocle学习镜头.到目前为止,我学到的是当你必须"修改"一个深层嵌套的case类结构但尚未找到一种方法根据条件"切断"嵌套结构的某些部分并返回一个新结构时,镜头很有用.这可能是通过Monocle吗?此外,我不确定Lenses是否能够帮助实现更好的Big O时间?

Tra*_*own 4

以下内容在性能方面基本上等同于您的实现,但可以说更清晰:

import monocle.Traversal, monocle.macros.GenLens
import monocle.function.all._, monocle.std.list._

val deptAddresses: Traversal[Department, List[Address]] =
  GenLens[Department](_.people)
    .composeTraversal(each)
    .composeLens(GenLens[Person](_.addresses))

val filterAddresses: Department => Department =
  deptAddresses.modify(_.filterNot(_.zipCode == 38978))
Run Code Online (Sandbox Code Playgroud)

这只是构建了一个遍历来导航到每个人的地址列表,以便您可以根据谓词对其进行修改。我不确定是否有更好的方法来执行过滤(因为邮政编码不作为唯一索引),但也许 Julien 会考虑其中一种。