2015-02-01 2 views
6

다른 시나리오에서 대규모 데이터 집합의 여러 하위 집합에 대해 작업해야하는 프로젝트가 있습니다. 코드를 작성한 방법에는 Collector 인터페이스와 클래스 DataCollector implements Collector이 있습니다. DataCollector 클래스는 하위 집합 생성 조건으로 인스턴스화되며 이러한 조건은 열거 형입니다.Java enums에 대한 논리 연산

데이터 세트가 1 백만 개의 영어 단어 세트이고, 홀수 개의 문자로 구성된 단어의 하위 세트에 대해 작업하고 싶습니다. 그럼, 다음을 수행하십시오 CollectionType

enum CollectionType { 
    WORDS_OF_ODD_LENGTH, 
    WORDS_OF_EVEN_LENGTH, 
    STARTING_WITH_VOWEL, 
    STARTING_WITH_CONSONANT, 
    .... 
} 

는 데이터 수집기가 인스턴스화되는 열거에 따라 java.util.Predicate를 호출 열거 클래스에게 있습니다

DataCollector dataCollector = new DataCollector(CollectionType.WORDS_OF_ODD_LENGTH); 
Set<String> fourLetteredWords = dataCollector.collect(); 

.

지금까지이 접근 방식은 강력하고 유연했지만 지금은 점점 더 복잡한 시나리오 (예 : 모음으로 시작하는 길이가 짝수 인 단어 수집)에 직면하고 있습니다. 이러한 모든 시나리오에 대해 새로운 CollectionType을 추가하는 것을 피하고 싶습니다. 내가 알아챈 점은 이러한 복잡한 시나리오 중 상당수가 단순한 시나리오의 논리적 연산 일뿐입니다 (예 : condition_1 && (condition_2 || condition_3)).

최종 사용자는 이러한 조건을 지정하는 사람이며 유일한 조건은 이러한 조건 집합을 지정할 수 있다는 것입니다. 에서와 같이 최종 사용자는 CollectionType 중에서 선택할 수 있습니다. 지금은 한 가지 조건 만 선택하는 능력에서 하나 이상의 능력을 선택하는 것으로 일반화하려고 노력하고 있습니다. 그 때문에, 나는 비슷한 것을 필요로한다.

DataCollector dataCollector = new DataCollector(WORDS_OF_ODD_LENGTH && 
               STARTING_WITH_VOWEL); 

그런 작업을 수행하기 위해 열거 형을 모델링하는 방법이 있습니까? 다른 아이디어 (예 : 열거 기반 접근 방식을 다른 것으로 스크랩해야합니다.

+0

내가이 경우 어떻게 할 것 인가, 'Predicate '로 다른 유형을 저장하고, 하나 또는 그 이상의 술어를 생성자와 저장소에 제공한다. 들판에서. 그런 다음, 해당 술어와 일치하는 모든 항목으로 서브 세트를 정의 할 수 있습니다. – DennisW

+2

구아바에는 기능 구성을위한 [유틸리티 기능 수] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Predicates.html)가 있습니다. 열거 형을 구성하는 데 사용할 수 있습니다. 'enum이 Predicate '을 구현했는지 확인하십시오. –

+0

이것은 Java 8을 사용할 수 있다고 가정합니다. – DennisW

답변

11

술어를 지원하고 술어를 지원하는 Java 8을 사용하는 것이 좋습니다.

enum CollectionType implements Predicate<String> { 
    WORDS_OF_ODD_LENGTH(s -> s.length() % 2 != 0), 
    WORDS_OF_EVEN_LENGTH(WORDS_OF_ODD_LENGTH.negate()), 
    STARTING_WITH_VOWEL(s -> isVowel(s.charAt(0))), 
    STARTING_WITH_CONSONANT(STARTING_WITH_VOWEL.negate()), 
    COMPLEX_CHECK(CollectionType::complexCheck); 

    private final Predicate<String> predicate; 

    CollectionType(Predicate<String> predicate) { 
     this.predicate = predicate; 
    } 

    static boolean isVowel(char c) { 
     return "AEIOUaeiou".indexOf(c) >= 0; 
    } 

    public boolean test(String s) { 
     return predicate.test(s); 
    } 

    public static boolean complexCheck(String s) { 
     // many lines of code, calling many methods 
    } 
} 

다음은

Predicate<String> p = WORDS_OF_ODD_LENGTH.and(STARTING_WITH_CONSONANT); 

또는 다섯 글자 단어가

Predicate<String> p = STARTING_WITH_VOWEL.and(s -> s.length() == 5); 

이 파일을 읽고이 필터를 사용하고 싶었 말 모음으로 시작하는 같은 술어를 작성할 수, 당신 할 수있다

List<String> oddWords = Files.lines(path).filter(WORDS_OF_ODD_LENGTH).collect(toList()); 

또는로드 할 때 인덱스 할 수 있습니다.

Map<Integer, List<String>> wordsBySize = Files.lines(path) 
           .collect(groupBy(s -> s.length())); 

열거 형을 술어로 설정 했더라도 이와 같이 사용법을 최적화 할 수 있습니다.

if (predicate == WORDS_OF_ODD_LENGTH || predicate == WORDS_OF_EVEN_LENGTH) { 
    // assume if the first word in a list of words of the same length 
    // then take all words of that length. 
    return wordsBySize.values().stream() 
           .filter(l -> predicate.test(l.get(0))) 
           .flatMap(l -> l.stream()).collect(toList()); 
} else { 
    return wordsBySize.values().stream() 
           .flatMap(l -> l.stream()) 
           .filter(predicate) 
           .collect(toList()); 
} 

즉, 당신은 몇 가지 조건을 인식하고 그들을 위해 최적화 할 수 있습니다 enum를 사용하여.(좋은 생각이든 아니든간에 내가 떠날 것이다)

+0

한 가지 질문 : 나의 술어는 좀 더 복잡합니다. 그래서 코드를 읽을 수 있도록 다른 곳에 정의해야합니다 (예 :'STARTING_WITH_VOWEL = _startingWithVowel', 여기서'private static _startingWithVowel = ... '는 10입니다. -15 라인 코드는 나중에 위치 함). 이로 인해 "잘못된 정방향 참조 오류"가 발생합니다. 이 술어를 보유 할 별도의 클래스를 작성해야합니까? 아니면 주변에 간단한 방법이 있습니까? –

+1

@ChthonicProject 위 예제에서와 같이 술어에서 메소드를 호출 할 수 있습니다. 람다가 한 라인 이상으로 될 필요가 없습니다 (또는 AFAICS 할당 또는 필드를 사용하십시오) –

+1

완벽! +1 'complexCheck' 예제를 추가합니다. –