2010-01-26 5 views
3

groupBy의 구현을 생각해 냈습니다.스칼라에서 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로 바꿀 수 있고 접이식 글꼴이 계속 작동 할 수 있습니다. –

답변

4

는, 당신은 아마이 작업을 수행 할 수 그 다음 :

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

그런 다음 다시 운동을 원할 수 있습니다. 이 경우 폴드 솔루션이 좋습니다.

+0

아주 멋지다! 내장 된 존재를 몰랐습니다. 다니엘 감사합니다! – Geo

+0

@Geo 'splitAt'와'span'도 유사하지만 다른 기준을 사용합니다. 첫 번째는'take'와'drop'을 나누고, 두 번째는'takeWhile'와'dropWhile'을 나눕니다. –

1

작은 힌트 : 결과 목록을 기능적/변경 불가능한 방식으로 계산하려면 folds을 사용하십시오.

2

나는 두 번만 필터링합니다. 당신이 진정으로 밖으로지도를 만들려면

in partition p 

: 당신이 술어 (즉, T => Boolean의 함수)로 그룹화 할 경우

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

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)) 
관련 문제