我正在尝试将以下Java代码段移植到Scala。它需要一个MyColor
个对象列表,并合并彼此增量内的所有对象。这似乎是一个可以使用Scala的一些功能部分优雅地解决的问题。有什么提示吗?
List<MyColor> mergedColors = ...;
MyColor lastColor = null;
for(Color aColor : lotsOfColors) {
if(lastColor != null) {
if(lastColor.diff(aColor) < delta) {
lastColor.merge(aColor);
continue;
}
}
lastColor = aColor;
mergedColors.add(aColor);
}
答案 0 :(得分:7)
这是另一个递归解决方案,它具有尾递归的优点(因此没有堆栈溢出的可能性)但是在缺点上会进行大量的列表操作,因此可能会浪费。最后反向调用是将输出颜色放回输入顺序,但如果您不关心顺序则不需要。
def processColors(colors: List[Color], delta: Double): List[Color] = {
def process(in: List[Color], accum: List[Color]): List[Color] = in match {
case x :: y :: ys if x.diff(y) < delta => process( x.merge(y) :: ys, accum )
case x :: xs => process( xs, x :: accum )
case Nil => accum
}
process(colors, Nil).reverse
}
答案 1 :(得分:4)
我假设您以某种方式将颜色排列在列表中,使得颜色空间中的颜色“接近”(即具有低diff
值)在列表中相邻。然后我会使用折叠:
val unmergedColors: List[MyColor] = ...
val mergedColors = (Nil:List[MyColor] /: unmergedColors)( (list,c) => {
list match {
case oldc :: rest if (oldc.diff(c) < delta) => oldc.merge(c) :: rest
case _ => c :: list
}
}).reverse
在这里,我假设merge
被改变为返回一个新颜色,即前两个合并的颜色(这样你的颜色是不可变的);否则,你在第一种情况下oldc.merge(c) ; list
。
让我们看看这里发生了什么。
我们从新颜色的空列表开始。然后,对于未合并列表中的每种颜色,我们有两种情况:
最后,由于我们将这些作为堆栈操作使用,我们通过反转列表来完成。
答案 2 :(得分:3)
在我看来,这个问题可能导致各种问题,无论问题是什么。例如:
但这里有一些使用递归的乐趣(虽然它不是尾递归当然可以这样做),例如:
type C = MyColor
type Cs = list[C]
def merge(val delta: Double, diff: (C, C) => Double, colors: Cs) : Cs = {
def _mergeHeadAndGTDiff(head: C, tail: Cs) : Cs = {
val (toMerge, rest) = tail.span(diff(head, _) < delta)
val newHead = (head :: toMerge).reduceLeft(_ merge _)
newHead :: (rest match {
case Nil => Nil
case x :: xs => _mergeHeadAndGTDiff(newHead, xs)
})
}
colors match {
case Nil => Nil
case x :: xs => _mergeHeadAndGTDiff(x, xs)
}
}
解决方案如下:
我认为这更适合Stream
。请注意,我假设列表最初由diff 排序,因为我使用的是span
。如果将其替换为partition
,则无需这样做。
答案 3 :(得分:1)
我试着折叠:
def merge(lotsOfColor: List[MyColor], delta: Double): List[MyColor] =
lotsOfColor.tail.foldLeft((List(lotsOfColor.head), lotsOfColor.head)) {
case ((mergedColors, lastColor), aColor) if (lastColor diff aColor) < delta =>
(mergedColors, lastColor merge aColor)
case ((mergedColors, _), aColor) => (aColor :: mergedColors, aColor)
}._1.reverse
或者,略有不同,
def merge(lotsOfColor: List[MyColor], delta: Double): List[MyColor] =
lotsOfColor.tail.foldLeft((List(lotsOfColor.head), lotsOfColor.head)) {
case ((mergedColors, lastColor), aColor) =>
if ((lastColor diff aColor) < delta)
(mergedColors, lastColor merge aColor)
else
(aColor :: mergedColors, aColor)
}._1.reverse
在Scala中使用ListBuffer还有另一个很酷的技巧,以避免在最后反向:
import scala.collection.mutable.ListBuffer
def merge(lotsOfColor: List[MyColor], delta: Double): List[MyColor] =
lotsOfColor.tail.foldLeft((ListBuffer(lotsOfColor.head), lotsOfColor.head)) {
case ((mergedColors, lastColor), aColor) if (lastColor diff aColor) < delta =>
(mergedColors, lastColor merge aColor)
case ((mergedColors, _), aColor) =>
mergedColors += aColor
(mergedColors, aColor)
}._1.toList