티스토리 뷰

programming language/java

Spliterator

rolroralra 2022. 9. 19. 11:31

Spliterator

  • 분할할 수 있는 반복자
  • splitable iterator
public interface Spliterator<T> {
    boolean tryAdvance(Consumer<? super T> action);
    Spliterator<T> trySplit();
    long estimateSize();
    int characteristics();
}

tryAdvance

  • 현재 요소에 Consumer를 수행 후, 다음 요소가 있는지 리턴

trySplit

  • 분할이 불가능한 경우, null 리턴
  • 분할 가능한 경우, 분할시킨 새로 생성한 Spliterator 리턴
  • 분할하고 나머지 부분 계속해서 trySplit 시도

estimateSize

  • 탐색해야할 요소의 개수를 리턴

Characteristic

Characteristic Description
ORDERED 리스트처럼 요소에 정해진 순서가 있으므로 Spliterator는 요소를 탐색하고 분할할 때 이 순서에 유의해야한다.
DISTINCT x, y 두요소를 방문했을 때 x.equals(y)는 항상 false를 반환한다.
SORTED 탐색된 요소는 미리 정의된 정렬 순서를 따른다.
SIZED 크기가 알려진 소스로 Spliterator를 생성했으므로 estimatedSize()는 정확한 값을 반환한다.
NON-NULL 탐색하는 모든 요소는 null이 아니다
IMMUTABLE 모든 요소는 불변이다. 즉 요소를 탐색하는 동안 요소를 추가하거나, 삭제하거나, 수정할 수 없다.
CONCURRENT 동기화 없이 Spliterator의 소스를 여러 쓰레드에서 동시에 고칠 수 있따.
SUBSIZED Spliterator 자신 그리고 분할되는 모든 Spliterator는 SIZED 특성을 가진다.

Example

    • 문장에서 단어 갯수 구하기 (스페이스 문자 기준)
    • 입력값

"Nel mezzo del cammin di nostra vita mi ritrovai in una selva oscura che la dritta via era smarrita "

  •  
  • 정답은 19

1. Procedural Programming

public static int countWordsIteratively(String s) {  
  int counter = 0;  
  boolean lastSpace = true;  
  for (char c : s.toCharArray()) {  
    if (Character.isWhitespace(c)) {  
      lastSpace = true;  
    }  
    else {  
      if (lastSpace) {  
        counter++;  
      }  
      lastSpace = Character.isWhitespace(c);  
    }  
  }  
  return counter;  
}

Input

SENTENCE = "Nel   mezzo del cammin  di nostra  vita mi  ritrovai in una  selva oscura che la  dritta via era   smarrita "

Execution

public static main(String[] args) {
    System.out.println("Found " + countWordsIteratively(SENTENCE) + " words");
}

Execution Result

Found 19 words  // OK

2. Custom Reducing with Stream

class WordCounter {  
  private final int counter;  
  private final boolean lastSpace;  

  public WordCounter() {  
    this(0, true);  
  }  

  public WordCounter(int counter, boolean lastSpace) {  
    this.counter = counter;  
    this.lastSpace = lastSpace;  
  }  

  public WordCounter accumulate(Character c) {  
    if (Character.isWhitespace(c)) {  
      return lastSpace ? this : new WordCounter(counter, true);  
    }  
    else {  
      return lastSpace ? new WordCounter(counter + 1, false) : this;  
    }  
  }  

  public WordCounter combine(WordCounter wordCounter) {  
    return new WordCounter(counter + wordCounter.counter, wordCounter.lastSpace);  
  }  

  public int getCounter() {  
    return counter;  
  }  
}

Execution

public static int countWordsWithCustomReducing(String s, boolean isParallel) {  
  Stream<Character> stream = IntStream.range(0, s.length()).mapToObj(s::charAt);  

  if (isParallel) {  
    stream = stream.parallel();  
  }  

  return countWordsWithCustomReducing(stream);  
}

public static main(String[] args) {
    System.out.println("Found " + countWordsWithCustomReducing(SENTENCE, false) + " words");
}

Execution Result

Found 19 words  // OK

Execution (With Parallel Stream)

public static main(String[] args) {
    System.out.println("Found " + countWordsWithCustomReducing(SENTENCE, false) + " words");
}

Execution Result (With Parallel Stream)

  • Wrong Answer
Found 43 words  // Wrong

3. Custom Spliterator

private static class WordCounterSpliterator implements Spliterator<Character> {  
  private static final int SPLIT_BUCKET_SIZE = 10;  
  private final String string;  
  private int currentIndex = 0;  

  private WordCounterSpliterator(String string) {  
    this.string = string;  
  }  

  @Override  
  public boolean tryAdvance(Consumer<? super Character> action) {  
    action.accept(string.charAt(currentIndex++));  
    return currentIndex < string.length();  
  }  

  @Override  
  public Spliterator<Character> trySplit() {  
    int currentSize = string.length() - currentIndex;  
    if (currentSize < SPLIT_BUCKET_SIZE) {  
      return null;  
    }  
    for (int splitIndex = currentSize / 2 + currentIndex; splitIndex < string.length(); splitIndex++) {  
      if (Character.isWhitespace(string.charAt(splitIndex))) {  
        Spliterator<Character> spliterator =  
            new WordCounterSpliterator(string.substring(currentIndex, splitIndex));  
        currentIndex = splitIndex;  
        return spliterator;  
      }  
    }  
    return null;  
  }  

  @Override  
  public long estimateSize() {  
    return string.length() - currentIndex;  
  }  

  @Override  
  public int characteristics() {  
    return ORDERED + SIZED + SUBSIZED + NONNULL + IMMUTABLE;  
  }  
}

Execution

public static int countWordsWithSpliterator(String s) {  
  Spliterator<Character> spliterator = new WordCounterSpliterator(s);  
  Stream<Character> stream = StreamSupport.stream(spliterator, true);  
  return countWordsWithCustomReducing(stream);  
}

public static main(String[] args) {
    System.out.println("Found " + countWordsWithSpliterator(SENTENCE) + " words");
}

Execution Result

Found 19 words  // OK

'programming language > java' 카테고리의 다른 글

Collection API  (0) 2022.09.20
Stream (java)  (0) 2022.09.18
Garbage Collector  (0) 2022.09.15
Java  (0) 2021.06.25
댓글