在case类列表中使用reduceLeft / foldLeft的更好方法

时间:2012-05-08 11:01:44

标签: scala

我的意图很简单:从用户对象列表中获取逗号分隔的emaild值。 我在Java中用for循环和if条件完成了这个。

现在我想在Scala中这样做,所以我尝试了这个。

case class User(name: String, email: String)

val userList = List(User("aaa", "aaa@aaa.com"),
                    User("bbb", "bbb@bbb.com"),
                    User("ccc", "ccc@ccc.com"))

现在

val mailIds = userList.foldLeft(""){(a: String, b: User) => ( b.email+","+a) } 

给出

ccc@ccc.com,bbb@bbb.com,aaa@aaa.com,

(请注意最后的逗号。)

val mailids = userList.map(x => x.email).reduceLeft(_+","+_)

给出

aaa@aaa.com,bbb@bbb.com,ccc@ccc.com

我尝试过只使用reduceLeft这样的

val emailids = userList.reduceLeft((emails: String, user: User) => emails+", "+user.email)

但它会抛出编译错误

type mismatch;  found   : (String, User) => java.lang.String  required: (java.io.Serializable, User) => java.io.Serializable

那么,在上述情况下是否有更好方式使用reduceLeft而没有map

2 个答案:

答案 0 :(得分:2)

不,reduceLeftfoldLeft,其中累加器是集合的第一个元素。在您的情况下,第一个元素是User,您必须为迭代的下一步传递相同类型的参数。这就是为什么你得到一个类型错配。
您可以在惰性集合中执行映射,并将其减少如下:

val mailIds = userList.view map (_.email) reduceLeft (_ + "," + _)

这将为您aaa@aaa.com,bbb@bbb.com,ccc@ccc.com而不创建第二个集合。 Jessie Eichar为此写了一篇非常好的tutorial

修改

没有延迟收藏的方法是删除最后一个逗号:

val rawMailIds = userList.foldLeft("")((acc, elem) => acc + elem.email + ",")
val mailIds = rawMailIds.substring(0, rawMailIds.length - 1)

答案 1 :(得分:0)

为什么不坚持使用map和reduce的组合?在任何情况下,您的问题是您的reduceLeft版本只需要一个字符串作为其初始值。