구아바 : Lists.filter () 함수가없는 이유는 무엇입니까?


86

이유가 있습니까?

Lists.transform()

하지만

Lists.filter()

?

목록을 올바르게 필터링하려면 어떻게합니까? 나는 사용할 수있다

new ArrayList(Collection2.filter())

물론,하지만 이렇게하면 내가 올바르게 이해한다면 내 주문이 동일하게 유지된다는 보장은 없습니다.


8
참고로 List.newArrayList (Iterables.filter (...))는 일반적으로 new ArrayList (Collection2.filter (...))보다 빠릅니다. ArrayList 생성자는 필터링 된 컬렉션에 대해 size ()를 호출하고 크기를 계산하려면 필터가 원본 목록의 모든 요소에 적용되어야합니다.
Jared Levy 2011

4
@JaredLevy 아마도 대신에 List.newArrayList(Iterables.filter(...))라고해야합니다 Lists.newArrayList(Iterables.filter(...)) .
Abdull 2013 년

답변:


57

반환 된 목록보기에 #get (index)와 같은 위험한 많은 수의 느린 메서드가 노출되기 때문에 구현되지 않았습니다 (성능 버그 초대). 그리고 ListIterator는 구현하기에도 고통 스러울 것입니다 ( 패치를 제출했지만 몇 년 전에 ).

인덱싱 된 메서드는 필터링 된 목록보기에서 효율적일 수 없기 때문에 필터링 된 Iterable을 사용하지 않는 것이 좋습니다.


7
목록보기가 반환 될 것이라고 가정합니다. 그러나 #filter는 새로운 구체화 된 목록을 반환하는 것으로 구현 될 수 있는데, 이는 실제로 Iterable에있는 것과 반대되는 목록에 대한 필터 메서드에서 기대하는 것입니다.
Felix Leipold

@FelixLeipold 이것은 그러나 물을 진흙탕 할 것입니다. 그대로, filter지속적으로 그의 여부 (의미 동작과 함께)보기를 의미 Iterables.filter, Sets.filter등 때문에 Iterables.filter쉽게와 결합 copyOf어떤에 ImmutableCollection, 내가 찾을이 좋은 디자인 트레이드 오프 (같은 별도의 방법 및 이름으로 오는 대 filteredCopy또는 이것 저것 , 간단한 유틸리티의 조합).
Luke Usherwood

37

당신이 사용할 수있는 Iterables.filter 은 확실히 순서를 유지할 것입니다 .

새 목록을 구성 하면 요소 (물론 참조 만)를 복사하게 되므로 원래 목록에 대한 라이브 뷰가되지 않습니다. 보기를 만드는 것은 매우 까다로울 수 있습니다. 다음 상황을 고려하십시오.

Predicate<StringBuilder> predicate = 
    /* predicate returning whether the builder is empty */
List<StringBuilder> builders = Lists.newArrayList();
List<StringBuilder> view = Lists.filter(builders, predicate);

for (int i = 0; i < 10000; i++) {
    builders.add(new StringBuilder());
}
builders.get(8000).append("bar");

StringBuilder firstNonEmpty = view.get(0);

그것은 모든 원본 목록을 반복하여 모든 것에 필터를 적용해야합니다. 조건 자 일치가 뷰의 수명 동안 변경되지 않도록 요구할 수 있다고 생각하지만 완전히 만족 스럽지는 않습니다.

(이것은 추측 일뿐입니다. 아마도 Guava 관리자 중 한 명이 진짜 이유를 알아낼 것입니다. :)


1
Collections2.filter.iterator을 호출하기 만하면 Iterables.filter결과는 동일합니다.
skaffman 2011

@skaffman : 어떤 경우에는 Iterables.filter명확성을 위해 버전을 사용합니다 .
Jon Skeet 2011

3
... view.size()나중에 코드에서 어딘가 가 필요하지 않는 한 :)
Xaerxess

28

new List(Collection2.filter())물론 사용할 수 는 있지만 이렇게하면 내 주문이 동일하게 유지된다는 보장이 없습니다.

이것은 사실이 아닙니다. Collections2.filter()느리게 평가되는 함수입니다. 필터링 된 버전에 액세스하기 시작할 때까지 실제로 컬렉션을 필터링하지 않습니다. 예를 들어 필터링 된 버전을 반복하는 경우 필터링 된 요소는 원래 컬렉션과 동일한 순서로 반복자에서 튀어 나옵니다 (분명히 필터링 된 요소 제외).

아마도 당신은 그것이 필터링을 미리 수행 한 다음 결과를 임의의 임의의 정렬되지 않은 컬렉션으로 덤프한다고 생각하고 있었을 것입니다.

따라서의 출력을 Collections2.filter()새 목록에 대한 입력으로 사용하면 원래 주문 유지됩니다.

정적 가져 오기 (및 Lists.newArrayList함수)를 사용하면 상당히 간결 해집니다.

List filteredList = newArrayList(filter(originalList, predicate));

반면이 있습니다 Collections2.filter열망으로 반복 기본 콜렉션,하지 않을 Lists.newArrayList 것이다 는 필터링 콜렉션의 모든 요소를 추출하고 그들에게 새로운에 복사 - ArrayList.


더 비슷합니다 : List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));또는 ie. List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
Xaerxess 2011

@Xaerxess : 죄송합니다, 예, 술어를 잊어 버렸습니다 ... 고정
skaffman

@Bozho : 감사합니다 ... 충분히 오래 걸렸습니다 :)
skaffman

12

Jon이 언급했듯이 Iterables.filter(..)or 를 사용할 수 Collections2.filter(..)있으며 라이브 뷰가 필요하지 않은 경우 ImmutableList.copyOf(Iterables.filter(..))or 를 사용할 수 Lists.newArrayList( Iterables.filter(..))있으며 예 주문이 유지됩니다. 부분에

관심이 있다면 https://github.com/google/guava/issues/505 에서 자세한 내용을 확인할 수 있습니다 .


6

다른 사람들이 말한 것을 요약하면 목록을 필터링하는 일반 래퍼를 쉽게 만들 수 있습니다.

public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
    return Lists.newArrayList(Iterables.filter(userLists, predicate));
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.