2017-11-20 2 views
1

목록이 Java 8로되어 있고 목록의 항목이 해당 기능의 조건을 충족하면 부울 결과를 반환하는 특정 필터링 기능이 있습니다. 나는 목록을 조건에 따라 여러 목록으로 나누고 싶다. 스트림 또는 다른 구조와 자바 8 위의 논리를 작성하는 청소기/더 나은 방법이 있나요Java는 부울 조건에 따라 여러 목록으로 목록을 분류합니다.

public void classifyItems(List<SomeType> mylist) { 
    //declare and initialize list1, list2, list3 
    //these lists will store items as per filtering conditions 

    mylist.forEach(item -> { 
     if (filteringFunction1(item) { 
      list1.add(item); 
     } 
     else if (filteringFunction2(item) { 
      list2.add(item); 
     } 
     else if (filteringFunction3(item) { 
      list3.add(item) 
     } 
    }); 

    //other operations on filtered lists 
} 

- 현재 내 코드는 같다? 나는 길고 다른 사다리에별로 행복하지 않다. 별도의 조건을 충족하는 품목에 대해 별도의 목록이 필요합니다.

+0

스트림 API에 파티션/그룹별로 * 같은 기능이 없습니다. * 여러 기능을 동시에 사용하면 가장 좋은 결과를 얻을 수 있습니다. – Eugene

+0

일치하지 않는 항목은 어떻게됩니까? 필터링 기능? 그들은 무시해야합니까/버려야합니까? – Henrik

답변

0

간편한 사용을 위해 필터가있는 기본 스트림을 사용할 수 있습니다. 이는 이해하기 쉽고 코드 크기를 줄이지 만 목록을 3 번 반복하는 단점이 있습니다.

public void classifyItems(List<String> mylist) { 
    List<String> filter1 = mylist.stream().filter(i -> filteringFunction1(i)).collect(Collectors.toList()); 
    List<String> filter2 = mylist.stream().filter(i -> filteringFunction2(i)).collect(Collectors.toList()); 
    List<String> filter3 = mylist.stream().filter(i -> filteringFunction3(i)).collect(Collectors.toList()); 
} 
+0

예, 목록을 세 번 반복하는 단점이 있습니다. – nishant

+0

목록의 크기가 중요하지 않으면 작은 코드 크기 및 가독성에 대한 성능 저하를 최소화 할 수 있습니다. –

0

스트림을 사용할 때 스트림 사용과 로직 코딩 사이의 균형을 찾아야합니다. 나는 아마 이렇게 할 것입니다.

enum Types { 
    Type1(list1) { 
     @Override 
     boolean filter(SomeType it) { 
      return false; 
     } 
    }, 
    Type2(list2) { 
     @Override 
     boolean filter(SomeType it) { 
      return true; 
     } 
    }, 
    Type3(list3) { 
     @Override 
     boolean filter(SomeType it) { 
      return false; 
     } 
    }; 

    final List<SomeType> theList; 
    Types(List<SomeType> theList) { 
     this.theList = theList; 
    } 

    List<SomeType> getList() { 
     return theList; 
    } 

    abstract boolean filter (SomeType it); 
} 

public void classifyItems(List<SomeType> mylist) { 
    mylist.stream().forEach(
      // walk all types. 
      i -> Arrays.stream(Types.values()) 
        // Choose only applicable types. 
        .filter(t -> t.filter(i)) 
        // Add it to the list. 
        .forEach(t -> t.getList().add(i)) 
    ); 
} 

이것은이 SomeType을 적용 할 수 있는지 여부를 검출하기 위해 제공함으로써 filterSomeType의리스트의 등록 정보를 인코딩하고 list는 것이 관련된다.

나는 의도 한대로 스트림을 걷거나 각 요소를 사용하여 stream만을 사용합니다.

+0

그것은 간접 접근의 또 다른 레벨입니다. 그러나 문제는 여전히 남아있다. – Eugene

1

현재 코드는 실제로 잘 읽을 수, 나는 훨씬 개선 될 수 있다고 생각하지 않습니다,하지만 당신은 groupingBy 수집기 사용으로 볼 수하십시오 MapList의 인스턴스

Map<String, List<SomeType>> grouped = mylist.stream().collect(
    Collectors.groupingBy(it -> { 
     if (filteringFunction1(item)) 
      return "CASE 1"; 

     if (filteringFunction2(item)) 
      return "CASE 2"; 

     if (filteringFunction3(item)) 
      return "CASE 3"; 

     return "DEFAULT"; 
    })); 

이 당신을 제공합니다 여기서 키는 각 값이로 분류 된 경우입니다.

지도에는 사례 이름이 포함 된 문자열 (예 : OldCurmudgeon의 대답에 enum)이 포함 된 것보다지도의 후보가 더 적합할까요?

2

, 술어의 목록을 수락 (또는 방법을 가변 인자 사용)

public void classifyItems(List<SomeType> mylist, List<Predicate<SomeType>> filterFuncs) { 
    int ffSize = filterFuncs.size(); 
    Map<Integer,List<SomeType>> classified = mylist.stream() 
      .collect(Collectors.groupingBy(item -> 
       IntStream.range(0, ffSize) 
         .filter(ix -> filterFuncs.get(ix).test(item)) 
         .findFirst().orElse(ffSize))); 

    //other operations on filtered lists 
} 

키가 filterFuncs 목록에서 술어의 위치에 해당하는지도와 같은 확장 가능한 솔루션을 허용 할 것은 너무 classified.get(0)는 "list1을 얻는다 ", classified.get(1)은"list2 "이되고, classified.get(ffSize)은 모든 조건 자와 일치하지 않는 모든 항목의 목록을 가져옵니다.

목록의 이전 술어와 일치하는 것이 후속 술어보다 우선 함을 나타내는 원래 코드의 논리를 유지합니다.