2012-12-14 2 views
10

컬렉션에서 가장 자주/공통 요소를 찾는 가장 좋은 방법은 무엇입니까? 예를 들어 :컬렉션에서 가장 빈번한/공통 요소 찾기?

list = List(1, 3, 4, 4, 2) 
list.mostCommon // => 4  !! This is what I want !! 

흠 .. 무엇 하나 할 수있는 것은 groupBy 첫째을하는 것입니다 length하여 다음 map을하고 가장 큰 하나를 선택합니다.

Map(1 -> List(1), 4 -> List(4, 4), 3 -> List(3), 2 -> List(2)) 
(...) 
Map(1 -> 1, 4 -> 2, 3 -> 1, 2 -> 1) // mapped by length. 4 -> 2 since there's two 4s 

을 그리고 결국, 가장 높은 숫자 (2)에 매핑되는 키 (4)를 선택 : 그럼 당신은 얻을 것이다. (중첩 된 질문 : 무엇이 가장 좋은 방법입니까?). 그러나 그것은 그러한 간단한 조작을위한 많은 작업처럼 보인다.?

이렇게하는 것이 더 낳고/더 관용적 인 방법이 있습니까?

+3

중첩 된 답 :'maxBy'를 사용합니다. – senia

+0

최대 값이 하나 이상일 수 있습니다.이 경우 최대 값으로지도를 필터링 할 수 있습니다. –

답변

20

내가 그런 말을 할 필요가 :

list.groupBy(identity).mapValues(_.size).maxBy(_._2)._1 

또는 단지 :

list.groupBy(identity).maxBy(_._2.size)._1 

정말 그다지 많은 작업처럼 보일하지 않습니다. 심지어

list.foldLeft(Map.empty[Int, Int].withDefaultValue(0)) { 
    case (m, v) => m.updated(v, m(v) + 1) 
}.maxBy(_._2)._1 

또는 당신이가는대로 최대 추적 : 당신은 카운트를 필요로 할 때 각각의 값에 대한 목록을 구축하는 오버 헤드 걱정 경우

, 당신은 다음을 수행 할 수 마지막에 추가 탐색을 피하기 위해 :

list.foldLeft(
    Map.empty[Int, Int].withDefaultValue(0), -1 -> Double.NegativeInfinity 
) { 
    case ((m, (maxV, maxCount)), v) => 
    val count = m(v) + 1 
    if (count > maxCount) (m.updated(v, count), v -> count) 
    else (m.updated(v, count), maxV -> maxCount) 
}._2._1 

이것은하지만, 분명히 훨씬 덜 읽을 수 위의 한 라이너보다, 그래서 당신이 보여줄 수없는 한, 벤치마킹, (즉, 그들과 함께 고집을 권장하지 않는 게 좋을 추측) 애플리케이션에서 병목 현상이 발생합니다.

+0

'maxBy' 전에'toSeq'이 필요 없습니다. – senia

+0

@senia. 아, 물론. 편집 됨. –

1

아니요, 최선의 방법이라고 생각합니다. 그러나

list.groupBy(identity).mapValues(_.size) 

는 예를 들어, 당신이 취할 수있는, 당신에게

Map(2 -> 1, 4 -> 2, 1 -> 2, 3 -> 1) 

을 제공합니다 ... 많은 일이 아니다 그 .maxBy(_._2) (편집 :! 감사 @Travis 브라운)과 튜플을 얻을 (4,2) 하나 - 라이너의 팬이라면

(대부분의 시간과 그것이 발생하는 방법을 여러 번 발생 수) :

scala> List(1, 3, 4, 1, 4, 2).groupBy(identity).mapValues(_.size).maxBy(_._2) 
res0: (Int, Int) = (4,2) 
+0

'4'가 가장 큰 값이기 때문에 한 줄짜리 줄이 여기에서만 작동합니다. 'maxBy'가 필요합니다 (내 대답 참조). –

+0

@TravisBrown : 네가 맞아, 고마워! –

+0

당신이 제공하는 한 - 라이너는이 접근법에 결함을 보여줍니다. 1과 4는 모두 가장 빈번한 값이지만 4 개만 주어진다. –

2

나는이 정말 어떤 좋네요 생각하지 않지만, 당신이 할 수 있습니다 :

List(1, 3, 4, 4, 2).groupBy(identity).maxBy(_._2.size)._1 

아니 좋은 솔루션을.당신이 원하는 것은 목록에 maxBy를 사용하는 몇 가지 방법은 다음과 같이 목록을 참조 :

val someList = List(1, 3, 4, 4, 2) 
someList.maxBy(x => list.count(_ == x)) 
+2

저는 대부분의 경우 작은 성능 향상에 비해 가독성을 선택하는 주창자입니다. 그러나 하위 쿼드 러티 문제에 대한 2 차 솔루션이 좋은 아이디어인지 확신 할 수 없습니다. –

0

다른 변형 :

val x = List(1, 3, 4, 1, 4, 2, 5, 5, 5) 
x.distinct.foldLeft((0,0))((a, b) => { 
    val cnt = x.count(_ == b); 
    if (cnt > a._1) (cnt, b) else a 
})._2 
관련 문제