2010-01-26 33 views
3

我想出这个实施groupBy在Scala中实现groupBy方法的替代方法?

object Whatever 
{ 
    def groupBy[T](in:Seq[T],p:T=>Boolean) : Map[Boolean,List[T]] = { 
     var result = Map[Boolean,List[T]]() 
     in.foreach(i => { 
      val res = p(i) 
      var existing = List[T]() // how else could I declare the reference here? If I write var existing = null I get a compile-time error. 
      if(result.contains(res)) 
       existing = result(res) 
      else { 
       existing = List[T]() 
      } 
      existing ::= i 
      result += res -> existing 
     }) 
     return result 
    } 
} 

,但它似乎并不十分Scalish(是这个词我在找?)给我。你可能会建议一些改进?

编辑:我收到的“暗示”关于折叠后,我实现了这种方式:

def groupFold[T](in:Seq[T],p:T=>Boolean):Map[Boolean,List[T]] = { 
     in.foldLeft(Map[Boolean,List[T]]()) ((m,e) => { 
      val res = p(e) 
      m(res) = e :: m.getOrElse(res,Nil) 
     }) 
} 

你觉得呢?

+0

折叠实现是非常有用的。请注意,您可以用普通类型U替换布尔值,折叠仍然可以工作! – 2010-01-26 20:59:43

回答

4

如果你想组一个谓语(即,T => Boolean功能),那么你可能只是想做到这一点:

in partition p 

如果你真的想创建一个映射出来的它,那么:

val (t, f) = in partition p 
Map(true -> t, false -> f) 

然后,你可能只是想要练习。在这种情况下,折叠解决方案很好。

+0

非常酷!不知道内建的存在。谢谢丹尼尔! – Geo 2010-01-26 20:55:06

+0

@Geo您可能还想看看'splitAt'和'span',它们做了类似的事情,但有着不同的标准。第一个分为“take”和“drop”,第二个分为“takeWhile”和“dropWhile”。 – 2010-01-26 23:26:32

1

小提示:使用folds以功能/不可变的方式计算结果列表。

2

我只是过滤两次。

object Whatever { 
    def groupBy[T](in: Seq[T], p: T => Boolean) : Map[Boolean,List[T]] = { 
    Map(false -> in.filter(!p(_)).toList , true -> in.filter(p(_)).toList) 
    } 
} 
+0

真的很好的实现! – Geo 2010-01-26 20:24:12

4

下面是使用foldLeft的示例。

scala> def group[T, U](in: Iterable[T], f: T => U) = { 
    | in.foldLeft(Map.empty[U, List[T]]) { 
    |  (map, t) => 
    |  val groupByVal = f(t) 
    |  map.updated(groupByVal, t :: map.getOrElse(groupByVal, List.empty)) 
    | }.mapValues(_.reverse) 
    | } 
group: [T,U](in: Iterable[T],f: (T) => U)java.lang.Object with scala.collection.DefaultMap[U,List[T]] 

scala> val ls = List(1, 2, 3, 4, 5) 
ls: List[Int] = List(1, 2, 3, 4, 5) 

scala> println(group(ls, (_: Int) % 2)) 
Map(1 -> List(1, 3, 5), 0 -> List(2, 4)) 

斯卡拉2.8报价在此标准库:当你有更多的价值比布尔具有

scala> println(ls.groupBy((_: Int) % 2)) // Built into Scala 2.8. 
Map(1 -> List(1, 3, 5), 0 -> List(2, 4))