[SCALA] 스칼라 : 객체 목록에서 중복 제거
SCALA스칼라 : 객체 목록에서 중복 제거
나는 모두 같은 클래스에서 인스턴스화 된 개체 목록 [오브젝트]의 목록을 가지고있다. 이 클래스는 고유 Object.property이어야 필드가 있습니다. 개체의 목록을 반복하고 동일한 속성을 가진 모든 객체 (하지만 첫 번째)를 제거하는 가장 깨끗한 방법은 무엇입니까?
해결법
-
==============================
1.
list.groupBy(_.property).map(_._2.head)
설명 : GROUPBY 방법은, 그룹핑을위한 키 요소를 변환하는 기능을 수용한다. 객체 => elem.property (컴파일러, X $ (1) 같은 것을 고유 한 이름을 생성) : _.property은 ELEM 단지 속기이다. 그래서 지금 우리가지도의지도가 [속성, 목록은 [] 객체]. 맵 [K는 V]에 이동 [(K를, V)]으로 연장된다. 그래서 그것은 목록처럼 통과하지만, 요소 튜플하다 할 수있다. 이것은 자바의지도 #의 entrySet ()와 유사합니다. 지도 상에있어서의 각 요소를 반복하고 여기에 함수를 적용함으로써 새로운 집합을 생성한다. (성질,리스트 [개체) => elem._2.head이 경우 함수 ELEM 대한 속기 _._ 2.head이다. _2 번째 요소를 반환 튜플 단순한 방법이다. 두 번째 요소는 목록 [개체]이며, 머리는 첫번째 요소를 반환
당신이 원하는 유형을로 결과를 얻으려면 :
import collection.breakOut val l2: List[Object] = list.groupBy(_.property).map(_._2.head)(breakOut)
간단히 설명하기 위해,지도는 실제로는 두 개의 인수, 함수 및 결과를 구성하는 데 사용되는 개체를 기대하고있다. 첫 번째 코드에서 암시 적으로 표시 범위 등의 미리 정의 된 값들의 목록에서 컴파일러에 의해 제공되기 때문에 사용자가 제 2 값을 참조하지 니펫. 그 결과는 일반적으로 컨테이너 매핑으로부터 얻어진다. 이것은 일반적으로 좋은 일이있다. 목록에지도 우리는 우리가 결과로 원하는 컨테이너를 표현하려면, 배열에지도 그러나이 경우 배열 등을 반환, 목록을 반환합니다. 브레이크 아웃 방법이 사용되는 곳이다. 이 빌더 만 원하는 결과 유형을 보면 (결과를 빌드 것)를 구성한다. 그것은 일반적인 방법이며 우리가 명시 적으로 목록 [오브젝트] 또는 순서 (개체 # 속성을 가정 유형의 속성이다)을 유지하기로 (L2)를 입력했기 때문에 컴파일러는 제네릭 형식을 유추 :
list.foldRight((List[Object](), Set[Property]())) { case (o, cum@(objects, props)) => if (props(o.property)) cum else (o :: objects, props + o.property)) }._1
foldRight 초기 결과를 허용하는 방법 및 요소를 수용하고 업데이트 된 결과를 돌려주는 함수이다. 이 방법은 각 요소에 함수를 적용하여 최종 결과를 반환에 따른 결과를 갱신하는 각 요소를 반복 할. 우리가 물체에 붙이는 때문에 우리는 (보다는 foldLeft으로 왼쪽에서 오른쪽으로) 오른쪽에서 왼쪽으로 이동 -이 O (1), 그러나 추기는 O (N). 또한, 여기에 좋은 스타일을 관찰 우리는 요소를 추출하는 패턴 일치를 사용하고 있습니다.
이 경우, 초기 결과는 빈리스트 및 세트의 쌍 (튜플)이다. 목록은 우리가 관심있는 결과이며, 세트는 우리가 이미 발생한 어떤 특성을 추적하는 데 사용됩니다. . 각 반복에서 우리는 세트 소품이 이미 설정에서,이 방법은 (적용 데프되어 적용) (재산을 포함 스칼라, OBJ (X)가 obj.apply (X로 번역되어 있는지 확인 A : A) :. 부울 즉 ) 요소를 수용하고 있는지 아닌지 참 / false를 반환합니다. 속성이 (이미 발생) 존재하는 경우, 결과는 그대로 반환됩니다. 그렇지 않으면 결과는 (:: 객체 O) 객체를 포함하도록 업데이트되고 속성이 기록됩니다 (소품 + o.property)
업데이트 : @andreypopp는 일반적인 방법을 원했다 :
import scala.collection.IterableLike import scala.collection.generic.CanBuildFrom class RichCollection[A, Repr](xs: IterableLike[A, Repr]){ def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]) = { val builder = cbf(xs.repr) val i = xs.iterator var set = Set[B]() while (i.hasNext) { val o = i.next val b = f(o) if (!set(b)) { set += b builder += o } } builder.result } } implicit def toRich[A, Repr](xs: IterableLike[A, Repr]) = new RichCollection(xs)
사용:
scala> list.distinctBy(_.property) res7: List[Obj] = List(Obj(1), Obj(2), Obj(3))
또한 우리는 빌더를 사용하는 것처럼이 꽤 효율적이다 있습니다. 당신이 정말로 큰 목록이있는 경우 정기적 세트와 벤치 마크 성능 대신 변경 가능한 HashSet의를 사용할 수 있습니다.
-
==============================
2.다음 순서를 유지 조금 비열한하지만 빠른 솔루션입니다 :
다음 순서를 유지 조금 비열한하지만 빠른 솔루션입니다 :
list.filterNot{ var set = Set[Property]() obj => val b = set(obj.property); set += obj.property; b}
이 내부적으로 VAR를 사용하지만, 나는 그것을 이해하고 foldLeft-솔루션을보다 쉽게 읽을 생각합니다.
-
==============================
3.스칼라 2.13부터 가장 콜렉션은 이제 특정 변형 함수를 적용한 후 중복 무시 시퀀스의 모든 요소를 반환 distinctBy 방법이 제공된다 :
스칼라 2.13부터 가장 콜렉션은 이제 특정 변형 함수를 적용한 후 중복 무시 시퀀스의 모든 요소를 반환 distinctBy 방법이 제공된다 :
list.distinctBy(_.property)
예를 들어 :
List(("a", 2), ("b", 2), ("a", 5)).distinctBy(_._1) // List((a,2), (b,2)) List(("a", 2.7), ("b", 2.1), ("a", 5.4)).distinctBy(_._2.floor) // List((a,2.7), (a,5.4))
-
==============================
4.또 하나 개의 솔루션
또 하나 개의 솔루션
@tailrec def collectUnique(l: List[Object], s: Set[Property], u: List[Object]): List[Object] = l match { case Nil => u.reverse case (h :: t) => if (s(h.property)) collectUnique(t, s, u) else collectUnique(t, s + h.prop, h :: u) }
-
==============================
5.순서를 유지하여 다음
순서를 유지하여 다음
def distinctBy[L, E](list: List[L])(f: L => E): List[L] = list.foldLeft((Vector.empty[L], Set.empty[E])) { case ((acc, set), item) => val key = f(item) if (set.contains(key)) (acc, set) else (acc :+ item, set + key) }._1.toList distinctBy(list)(_.property)
-
==============================
6.나는 그것이 하나의 중간 단계, GROUPBY와 함께 작동하도록하는 방법을 발견 :
나는 그것이 하나의 중간 단계, GROUPBY와 함께 작동하도록하는 방법을 발견 :
def distinctBy[T, P, From[X] <: TraversableLike[X, From[X]]](collection: From[T])(property: T => P): From[T] = { val uniqueValues: Set[T] = collection.groupBy(property).map(_._2.head)(breakOut) collection.filter(uniqueValues) }
이처럼 사용
scala> distinctBy(List(redVolvo, bluePrius, redLeon))(_.color) res0: List[Car] = List(redVolvo, bluePrius)
IttayD 최초의 솔루션과 유사하지만 고유 한 값의 설정에 따라 원래의 콜렉션을 필터링합니다. GROUPBY 하나,지도 하나와 필터 하나를 내 기대가 맞다면,이 세 가지 순회 않습니다. 그것은 원래의 콜렉션의 순서를 유지하지만 반드시 각 속성에 대한 첫 번째 값을 고려하지 않습니다. 예를 들면, (bluePrius, redLeon) 대신에 목록을 반환 할 수 있었다.
물론, IttayD의 솔루션은 하나의 통과를 않기 때문에 여전히 빠릅니다.
내 솔루션은 컬렉션이 실제로 동일한 자동차가있는 경우, 모두 출력 목록에있을 것입니다 단점이있다. 이 필터를 제거하고, [T]에서 타입 직접 uniqueValues 반환하여 고정 될 수있다. 그러나, 그것은 CanBuildFrom 것 같아 [에서에서 맵 [P, [T], T [T는]] 존재하지 않는 ... 제안을 환영합니다!
-
==============================
7.위의 좋은 답변을 많이합니다. 그러나 distinctBy는하지만 그리 명확하지 않다 장소에서, 스칼라 이미 사용 중입니다. 아마도 당신은 같이 사용할 수 있습니다
위의 좋은 답변을 많이합니다. 그러나 distinctBy는하지만 그리 명확하지 않다 장소에서, 스칼라 이미 사용 중입니다. 아마도 당신은 같이 사용할 수 있습니다
def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = scala.reflect.internal.util.Collections.distinctBy(xs)(f)
from https://stackoverflow.com/questions/3912753/scala-remove-duplicates-in-list-of-objects by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라 : mapValues이보기를 생산하고 안정적인 대안이 왜? (0) | 2019.11.01 |
---|---|
[SCALA] 자바에서 구현 방법과 스칼라 특성을 사용하여 (0) | 2019.11.01 |
[SCALA] 스칼라의 방법 대 기능 (0) | 2019.11.01 |
[SCALA] 왜 스칼라에서 패턴 매칭이되지 변수와 함께 작동합니까? (0) | 2019.11.01 |
[SCALA] flatMap /지도 변환에 대한-이해와 혼란 (0) | 2019.11.01 |