У меня есть 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)
, который работает. Моя первая забота была с линией vals.dropRight(1) ++ Seq(new Interval(fst.getStart, snd.getEnd))
Я подозреваю, dropRight
является O(n - m)
где n = |vals|
и m = 1
в этом случае.
Эта реализация становится дорогой, если |a|
находится в порядке сотен тысяч и более. Фактически vals ++ Seq(e)
также является проблемой, если он n + 1
для каждого a[i]
.
Во-первых, моя оценка правильная?
Во-вторых, есть ли более эффективный способ написать это без изменяемых структур данных?
Я написал это из контекста, в котором он используется, фактическое приложение находится в работе Spark (так что foldLeft
будет складываться на RDD[MyType]
).
EDIT: Совсем забыл нет foldLeft
на RDD
(игнорировать искру мне придется придумать другой способ, но я по-прежнему заинтересован в ответ на это, минус тот факт, что не будет работать в Спарк)
Существует не foldLeft или dropRight на RDD. –
Спасибо, полностью забыл, что на RDD нет 'foldLeft' – zcourts