gpt4 book ai didi

Scalaz 流分组排序数据库结果

转载 作者:行者123 更新时间:2023-12-05 00:28:18 25 4
gpt4 key购买 nike

我在我的代码中看到了一个常见的模式。我已经对数据库中的结果进行了排序,我需要以嵌套结构发出它们。我希望它可以流式传输,因此我希望一次在内存中保留尽可能少的记录。使用 TravesableLike.groupBy 假定数据未排序,因此它不必要地填充可变映射。我想保持这种真正的流式传输。 scalaz-stream 在这里有用吗?

val sql = """select grandparent_id, parent_id, child_id
from children
where grandparent_id = ?
order by grandparent_id, parent_id, child_id"""

def elementsR[P, R](invoker: Invoker[P, R], param: P): Process[Task, R] =
// Invoker.elements returns trait CloseableIterator[+T] extends Iterator[T] with Closeable
resource(Task.delay(invoker.elements(param)))(
src => Task.delay(src.close)) { src =>
Task.delay { if (src.hasNext) src.next else throw End }
}

def dbWookie {
// grandparent_id, (grandparent_id, parent_id, child_id)
val invoker = Q.query[Int, (Int, Int, Int)](sql)
val es = elementsR(invoker, 42)

// ?, ?, ?

// nested emits (42, ((35, (1, 3, 7)), (36, (8, 9, 12))))
}

我在 Process 上没有看到太多像 foldLeft 和 scanLeft 这样的函数,所以我不确定如何检测 Grandparent_id、parent_id 或 child_id 何时发生变化并发出一个组。有任何想法吗?

最佳答案

我认为您想要的东西与 chunkBy 的工作方式类似. chunkBy每当谓词函数的结果从 true 翻转时发出一个块至 false .

您可以从比较 bool 值到比较输入的某个任意函数的结果来概括这一点。因此,只要应用于输入的此函数的值发生变化,您就会有一个进程发出一个块:

def chunkOn[I, A](f: I => A): Process1[I, Vector[I]] = {
def go(acc: Vector[I], last: A): Process1[I,Vector[I]] =
await1[I].flatMap { i =>
val cur = f(i)
if (cur != last) emit(acc) then go(Vector(i), cur)
else go(acc :+ i, cur)
} orElse emit(acc)
await1[I].flatMap(i => go(Vector(i), f(i)))
}

REPL 中的快速脏测试,使用 Identity monad 立即强制评估:
scala> import scalaz.stream._, scalaz.Id._
import scalaz.stream._
import scalaz.Id._

scala> val rows = Seq(('a, 'b, 'c), ('a, 'b, 'd), ('b, 'a, 'c), ('b, 'd, 'a))
rows: Seq[(Symbol, Symbol, Symbol)] = List(('a,'b,'c), ('a,'b,'d), ('b,'a,'c), ('b,'d,'a))

scala> val process = Process.emitSeq[Id, (Symbol, Symbol, Symbol)](rows)
process: scalaz.stream.Process[scalaz.Id.Id,(Symbol, Symbol, Symbol)] =
Emit(List(('a,'b,'c), ('a,'b,'d), ('b,'a,'c), ('b,'d,'a)),Halt(scalaz.stream.Process$End$))

scala> process |> chunkOn(_._1)
res4: scalaz.stream.Process[scalaz.Id.Id,scala.collection.immutable.Vector[(Symbol, Symbol, Symbol)]] =
Emit(List(Vector(('a,'b,'c), ('a,'b,'d))),Emit(List(Vector(('b,'a,'c), ('b,'d,'a))),Halt(scalaz.stream.Process$End$)))

正如您所建议的, chunkWhen在当前值和最后一个值上使用谓词,并在计算结果为 false 时发出一个块.
def chunkWhen[I](f: (I, I) => Boolean): Process1[I, Vector[I]] = {
def go(acc: Vector[I]): Process1[I,Vector[I]] =
await1[I].flatMap { i =>
acc.lastOption match {
case Some(last) if ! f(last, i) => emit(acc) then go(Vector(i))
case _ => go(acc :+ i)
}
} orElse emit(acc)
go(Vector())
}

尝试一下:
scala> process |> chunkWhen(_._1 == _._1)
res0: scalaz.stream.Process[scalaz.Id.Id,Vector[(Symbol, Symbol, Symbol)]] =
Emit(List(Vector(('a,'b,'c), ('a,'b,'d))),Emit(List(Vector(('b,'a,'c), ('b,'d,'a))),Halt(scalaz.stream.Process$End$)))

关于Scalaz 流分组排序数据库结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19103388/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com