我根据条件有一个我想要减少的特定类型的列表。我有一个类型,其中Interval是一个具有开始和结束的DateTime间隔:
case class MyType(a: Interval, value: Double)
我有一个List [MyType]条目,我希望根据包含相同DateTime和值的MyType将其缩减为List [MyType]。我不想两次查看我已经做过的列表。
说我有:
val a = MyType(interval1, 2)
val b = MyType(interval2, 2)
val c = MyType(interval3, 1)
val d = MyType(interval4, 6)
val e = MyType(interval5, 2)
val original = List(a, b, c, d, e)
我现在必须根据以下条件减少原始列表:
1. interval should be continuous, then take the start of the first entry and the end of the second entry
2. the double value should be the same
因此假设interval1,interval2是连续的,结果应如下所示:
val result = Seq(MyType(new Interval(a.interval.start, b.interval.end),2), c, d, e)
是否有更优雅的解决方案或想法?
答案 0 :(得分:4)
在reduce函数中,检查条件是否为真,如果是,则返回当前累加器而不是你计算的值。
这里是你如何只对偶数求和:
Seq(1,4,6,3).foldLeft(0)( (acc, a) =>
if (a % 2 == 0) acc + a else acc
)
res5: Int = 10
对编辑过的问题的回复:看来你有一些条件必须要遵守这些要素。然后,您可以应用函数.sliding
。
Seq(a,b,c,d,e).sliding(2).foldLeft(0)(
case (acc, Seq(MyType(ai, a), MyType(bi, b))) =>
if (ai.max == bi.min) acc + a else acc
)
Buuut ...... 您可能已经猜到它不会像您希望的那样高效。我希望你没有做任何过早的优化,因为你知道,这是所有邪恶的根源。但是如果你真的需要性能,可以用while
循环重写代码(回退到Java)。
答案 1 :(得分:2)
这应该有效:
def reduce(xs: List[MyType]) = {
xs match {
case a :: b :: tail =>
if(a.interval.end == b.interval.start && a.value == b.value)
reduce(MyType(new Interval(a.interval.start, b.interval.end) a.value) :: tail)
else
a :: reduce(b :: tail)
case _ => xs
}
}
if
条件可能需要稍微调整,具体取决于您的确切需求,但算法应该有效。
给出一个列表xs
a
和b
可以合并到c
,请将它们合并,然后使用xs = c :: tail
a
和b
,请尝试减少第一个元素,并将结果附加到a
xs
答案 2 :(得分:0)
请注意,您的任务可能会产生多个不同的解决方案,这些解决方案无法进一步降低。
因此,您将获得一组解决方案:Set[Set[MyType]]
我使用Set[MyType]
代替提议的List[MyType]
和Seq[MyType]
,因为顺序并不重要,我的答案需要比较不同的解决方案(以避免重复)。
我的回答并不是对项目顺序做出假设,任何顺序都可以。
除此之外为了简化代码,我已将Interval
替换为2个字段from
和to
,这些字段可以轻松转换。
以下是减少代码:
case class MyType(from: Long, to: Long, value: Double)
object MyType {
//Returns all possible varians of reduced source.
//If reduction is not possible, returns empty set.
private def strictReduce(source: Set[MyType]): Set[Set[MyType]] = {
if (source.size <= 1) {Set.empty} else {
val active = source.head //get some item
val otherItems = source.tail //all other items
val reducedWithActive: Set[Set[MyType]] = otherItems.flatMap {
case after if active.to == after.from =>
//we have already found a reduction (active->after),
// so further reductions are not strictly required
reduce(otherItems - after + MyType(active.from, after.to, active.value))
case before if before.to == active.from =>
//we have already found a reduction (before->active),
// so further reductions are not strictly required
reduce(otherItems - before + MyType(before.from, active.to, active.value))
case notContinuos => Set.empty[Set[MyType]]
}
//check if we can reduce items without active
val reducedIgnoringActive = strictReduce(otherItems).
//if so, re-insert active and try to reduce it further, but not strictly anymore
flatMap (reducedOther => reduce(reducedOther + active))
reducedWithActive ++ reducedIgnoringActive
}
}
//Returns all possible varians of reduced source.
//If reduction is not possible, returns source as single result.
private def reduce(source: Set[MyType]): Set[Set[MyType]] = strictReduce(source) match {
case empty if empty.isEmpty => Set(source)
case reduced => reduced
}
//Reduces source, which contains items with different values
def reduceAll(source: Set[MyType]): Set[Set[MyType]] = source.
groupBy(_.value). //divide by values, because they are not merge-able
mapValues(reduce). //reduce for every group
values.reduceLeft((solutionSetForValueA, solutionSetForValueB) =>
//merge solutions for different groups
for(subSolutionForValueA <- solutionSetForValueA;
subSolutionForValueB <- solutionSetForValueB)
yield (subSolutionForValueA ++ subSolutionForValueB) //merge subSolutions
)
}
以下是使用它的示例:
object Example extends App {
val source = Set(
MyType(0L, 1L, 1.0),
MyType(1L, 2L, 2.0), //different value
MyType(1L, 3L, 1.0), //competing with next
MyType(1L, 4L, 1.0), //competing with prev
MyType(3L, 5L, 1.0), //joinable with pre-prev
MyType(2L, 4L, 2.0), //joinable with second
MyType(0L, 4L, 3.0) //lonely
)
val solutions: Set[Set[MyType]] = MyType.reduceAll(source)
//here you could choose the best solution (for example by size)
//printing out
solutions.foreach(solution => println(solution.toList.sortBy(_.from).sortBy(_.value).
map(item => s"${item.from}->${item.to}(${item.value})").mkString(", ")))
}
我的结果是:
0->5(1.0), 1->4(1.0), 1->4(2.0), 0->4(3.0)
0->4(1.0), 1->5(1.0), 1->4(2.0), 0->4(3.0)
答案 3 :(得分:0)
以下是我提出的建议:
end