2011-06-18 63 views
6

我有一个List [Number]。它包含Number - Int,Double等不同子类的值。我想将所有的值汇总在一起。如果列表只包含Int,我希望结果是一个Int。如果有混合,我想遵循正常的Scala规则:Int + Double = Double(依此类推)。将数字加在一起

我已经试过这样:

val result = list.reduceLeft(_ + _) 

这甚至不是编译。 Number没有定义另一个Number的方法。

我该如何做到这一点?

安德烈斯

+1

以供将来参考,它被认为是更好的形式来问。在Scala邮件列表或者StackOverflow上都可以找到一个问题,而不是两者。对于像这样的问题但是,StackOverflow通常是更好的选择,因为其他人比在邮件列表存档中更容易从问题和答案中学习! –

+1

我站好了。不会有下一次。感谢所有的帮助,并且在教我礼仪方面如此温柔。 – Andres

回答

9

复制从Scala的邮件列表,其中的问题是,第一我的回答问:

Number是一个Java类,并从自身转换成原始类型没有任何功能一旁。不幸的是,Scala的AnyVal除了标记原始类型外没有做任何其他的事情,Scala的Numeric[T]只知道它自己的类型,而不是混合类型。

所以你留下了相当不愉快的模式匹配;最短的语法,如果你确信你只需要处理双和int是:

list.reduceLeft((l,r) => (l: Any, r: Any) match { 
    case (li: Int, ri: Int) => li + ri 
    case _ => l.doubleValue + r.doubleValue 
}) 

请注意,我铸造Any得到Scala的模式匹配做拆箱为我们;如果你把它作为数字,你必须模式匹配java.lang.Integer然后valueOf它,这是一个痛苦。

如果你想要更多,你就必须建立相应的优惠:

list.reduceLeft((l,r) => (l: Any) match { 
    case li: Int => (r: Any) match { 
    case ri: Int => li + ri 
    case rf: Float => li + rf 
    case rl: Long => li + rl 
    case _ => li + r.doubleValue 
    } 
    case lf: Float => /* etc. */ 
}) 

如果你要做多一点这更多,你可能会更好过有利于自己的放弃Numeric包装类,知道如何通过适当的促销加入自己;那么你可以只写一次模式匹配,然后在你的列表解析中返回使用+。

sealed abstract class Addable { 
    def +(a: Addable): Addable 
} 

final case class MyInt(value: Int) extends Addable { 
    def +(a: Addable) = a match { 
    case MyInt(i) => MyInt(value + i) 
    case MyFloat(f) => MyFloat(value + f) 
    ... 
    } 
} 

final case class MyFloat(value: Float) extends Addable { 
    def +(a: Addable) = a match { 
    case MyInt(i) => MyFloat(value + i) 
    ... 
    } 
} 

... 

这种方法的一个轻微的好处是,你可以决定,以促进值比标准不同的方式(例如,您可能决定浮动+长=双,因为浮动真的不切出。保持多长的数字精度,并做MyDouble(value.toDouble + f.toDouble),例如

这一切都颇为尴尬,既不是Java和斯卡拉真的为混合型数学支持

0

通过减少Double的List。

不要使用类Number,你实际上无法用它做任何事情。它甚至不是一个Scala类,它是一个Java类。

+0

我想知道为什么你是低调的。像'num.view.map(_。doubleValue).sum'这样做是合理的。 – soc

+0

@SOC我做过了吗?也许这是一个错误。我找不到它来投票,我在这里还是比较新的。 –