私はSeq
のインターバルを持っており、オーバーラップしたもの同士を互いに崩壊させたいと思っています。 私はこれを書いた:効率的にオーバーラップするJodaTimeインターバルを見つける
val today = DateTime.now()
val a: Seq[Interval] = Seq(
new Interval(today.minusDays(11), today.minusDays(10)), //1 day interval ending 10 days ago
new Interval(today.minusDays(10), today.minusDays(8)), //2 day interval ending 8 days ago, overlaps with above
new Interval(today.minusDays(7), today.minusDays(5)), //2 day interval ending 5 days ago, DOES NOT OVERLAP
new Interval(today.minusDays(4), today.minusDays(1)), //3 day interval ending 1 day ago, DOES NOT OVERLAP above
new Interval(today.minusDays(4), today) //4 day interval ending today, overlaps with above
)
val actual = a.sortBy(_.getStartMillis).foldLeft(Seq[Interval]())((vals, e) => {
if (vals.isEmpty) {
vals ++ Seq(e)
} else {
val fst = vals.last
val snd = e
if (snd.getStart.getMillis <= fst.getEnd.getMillis) /*they overlap*/ {
vals.dropRight(1) ++ Seq(new Interval(fst.getStart, snd.getEnd)) //combine both into one interval
} else {
vals ++ Seq(e)
}
}
})
val expected = Seq(
new Interval(today.minusDays(11), today.minusDays(8)),
new Interval(today.minusDays(7), today.minusDays(5)),
new Interval(today.minusDays(4), today)
)
println(
s"""
|Expected: $expected
|Actual : $actual
""".stripMargin)
assert(expected == actual)
これは働いています。私の最初の懸念は、私がdropRight
がO(n - m)
どこn = |vals|
この場合のm = 1
である疑いがある行 vals.dropRight(1) ++ Seq(new Interval(fst.getStart, snd.getEnd))
していました。
|a|
が数十万以上のオーダーの場合、この実装は高価になります。実際にvals ++ Seq(e)
も、それぞれa[i]
に対してn + 1
の場合に問題になります。
まず、私の評価は正しいですか?
第2に、変更可能なデータ構造なしでこれを書くより効率的な方法がありますか?
実際のアプリケーションが使用されている文脈からこれを書きましたが、実際のアプリケーションはSparkジョブにあります(foldLeft
はRDD[MyType]
に折りたたまれます)。
EDIT:完全RDD
にはfoldLeft
はありません忘れてしまった(スパークを無視し、私は別の方法を考える必要がありますが、私はまだこの答えに興味があり、マイナスの事実は、それはスパークに動作しません。 )
RDDにfoldLeftまたはdropRightはありません。 –
ありがとう、RDDに 'foldLeft'がないことを完全に忘れてしまった – zcourts