【问题标题】:Lazy filter + flatMap + concat惰性过滤器 + flatMap + concat
【发布时间】:2020-01-05 22:03:48
【问题描述】:

进行惰性转换的最佳方法是什么(不创建中间集合) 当

  1. 在平面图之前和之后进行过滤 平面地图

  2. 连接集合

通常我使用 withFilter 进行这种惰性过滤,但在更复杂的用例中它并不完全有效

过滤器 + flatMap

1) 幼稚的方法

 case class Item(size: Int, color: String)
 // Assume an order can have a lot of items
 case class Orders(price:Int, country: String, items: Seq[C])

 val orders: Seq[Orders]
 val ca = orders.filter(_.country = "CA").flatMap(_.items).filter(_.size > 4) 
 val rest = orders.filter(_.country != "CA").flatMap(_.items).filter(_.size > 6) 
 val res = (ca ++ rest).filter(_.color == "red").take(100)

2) 单一路径,但为每个订单创建中间项目集合。而且我认为 flatMap 也会产生一个集合

 orders.flatMap {
    case order if order.country = "CA") => order.items.filter(_.size > 4)
    case order                          => order.items
 }.withFilter(_.color == "red").take(100)

3) 迭代器。但我不能 100% 确定它会如何执行

 orders.iterator.flatMap {
    case order if order.country = "CA") => order.items.iterator.filter(_.size > 4)
    case order                          => order.items.iterator
 }.filter(_.color == "red").take(100)

4) 流。

 orders.toStream.flatMap {
    case order if order.country = "CA") => order.items.toStream.filter(_.size > 4)
    case order                          => order.items.toStream
 }.filter(_.color == "red").take(100)

5)视图:不确定是否会为每个订单中的项目创建中间集合(我认为会),而且总的来说我不喜欢视图(忘记“强制”会导致错误)

orders.view.flatMap {
        case order if order.country = "CA") => order.items.filter(_.size > 4)
        case order                          => order.items
     }.filter(_.color == "red").take(100)

连接

类似的选项,但用于

val items1 = items.filter(filter1)

val items2 = items.filter(filter2)
val items3 = items.filter(filter3)
val res = (items1 ++ items2 ++ items3).filter(_.color == "Red").take(100)

【问题讨论】:

  • 可能 Stream 将是最节省内存的。但赌注是进行基准测试,特别是如果这对您非常重要。另外,您可能想给fs2 看看。
  • 查看是您的最佳选择。视图不会创建新集合。您可以从这里的源代码中看到github.com/scala/scala/blob/v2.13.0/src/library/scala/… 对视图的每个操作都会创建一个包含函数或其他必要信息的新普通对象,但不会创建集合。

标签: scala scala-collections


【解决方案1】:

解决方案只是对类进行规范化吗?在您的示例中,您基本上有一个嵌套序列,并且要从嵌套序列变为一个序列,您需要在某个时候展平。

解决方案可以是 List[Tuple2[Order, Item]],从 Order 中删除 item

这样你就可以做一个collect

例如:

object Main {

  case class Item(size: Int, color: String)
  case class Order(price:Int, country: String)

  def main(args: Array[String]): Unit = {
    val orders: Seq[Tuple2[Order, Item]] = Seq(Order(0, "CA") -> Item(5, "red"), Order(0, "GB")-> Item(1, "blue"))

    val filtered: Seq[Item] = orders.collect {
      case (order, item) if order.country == "CA" && item.size > 4 && item.color == "red" => item
    }

    println(orders)
    println(filtered)
  }
}

// Output:
// List((Order(0,CA),Item(5,red)), (Order(0,GB),Item(1,blue)))
// List(Item(5,red))

Try it online!

【讨论】:

    猜你喜欢
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    • 1970-01-01
    • 2017-01-28
    • 1970-01-01
    相关资源
    最近更新 更多