구아바 : 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.