RxJava でズンドコキヨシ(window or buffer 使用)

調子に乗って RxJava でもやってみた。

がんばって Observable.window を使ってみた。

//zondoko.java
// なんちゃってラムダ使用。あと Android。
public void doZondoko() {
    final Random random = new Random();
    final List<String> PATTERN = Arrays.asList("ずん", "ずん", "ずん", "ずん", "どこ");
    final String K = "キ・ヨ・シ!";

    Observable.concat( // ※ の Observable<List<String>> を直列に連結
        Observable.interval(500, TimeUnit.MILLISECONDS)
            .map(_ -> random.nextInt(2) == 0 ? "ずん" : "どこ") // ランダムに ずん or どこ
            .window(PATTERN.size(), 1) // 要素数5のWindowを1ずつズラしてく
            .map(window -> window.toList())) // Observable<Observable<String>> を Observable<List<String>> に変換 ※
        .flatMap(window -> {
            if (sequenceEqual(window, PATTERN)) { // パターンと一致していたら…
                final List<String> says = new ArrayList<>();
                says.addAll(window);
                says.add(K);                      // キ・ヨ・シ!を追加
                return Observable.concat(
                        Observable.just(says),
                        Observable.just(Collections.<String>emptyList())); // 終了判定用の空リスト
            } else {
                return Observable.just(window);
            }
        })
        .takeWhile(says -> !says.isEmpty())  // 空リストになるまで繰り返す
        .subscribe(says -> Log.d(TAG, dump(says)));
}

/** リストとリストの要素一致 */
private boolean sequenceEqual(List<String> listA, List<String> listB) {
    Iterator<String> iterA = listA.iterator();
    Iterator<String> iterB = listB.iterator();

    while (iterA.hasNext() && iterB.hasNext()) {
        if (iterA.next() != iterB.next()) {
            return false;
        }
    }
    return (!iterA.hasNext() && !iterB.hasNext());
}

/** リスト内容をダンプ */
private String dump(List<String> list) {
    final StringBuilder b = new StringBuilder();
    for (String s : list) {
        if (!TextUtils.isEmpty(b.toString())) {
            b.append(", ");
        }
        b.append(s);
    }

    return b.toString();
}

どこ, ずん, どこ, どこ, ずん

ずん, どこ, どこ, ずん, どこ どこ, どこ, ずん, どこ, ずん どこ, ずん, どこ, ずん, どこ ずん, どこ, ずん, どこ, どこ どこ, ずん, どこ, どこ, ずん ずん, どこ, どこ, ずん, ずん どこ, どこ, ずん, ずん, ずん どこ, ずん, ずん, ずん, ずん ずん, ずん, ずん, ずん, どこ, キ・ヨ・シ!

「window(5, 1) -> toList -> concat してるならそれは buffer(5, 1) やんけ」というのを こちら で知って、 buffer 版も書いてみた。

//Zondoko_buffer.java
public void doZondoko() {
    final Random random = new Random();
    final List<String> PATTERN = Arrays.asList("ずん", "ずん", "ずん", "ずん", "どこ");
    final String K = "キ・ヨ・シ!";

    Observable.interval(500, TimeUnit.MILLISECONDS)
        .map(_ -> random.nextInt(2) == 0 ? "ずん" : "どこ") // ランダムに ずん or どこ
        .buffer(PATTERN.size(), 1) // 要素数5のBufferを1ずつズラしてく
        .flatMap(buf -> {
            if (sequenceEqual(buf, PATTERN)) { // パターンと一致していたら…
                final List<String> says = new ArrayList<>();
                says.addAll(buf);
                says.add(K);                      // キ・ヨ・シ!を追加
                return Observable.concat(
                        Observable.just(says),
                        Observable.just(Collections.<String>emptyList())); // 終了判定用の空リスト
            } else {
                return Observable.just(buf);
            }
        })
        .takeWhile(says -> !says.isEmpty())  // 空リストになるまで繰り返す
        .subscribe(says -> Log.d(TAG, dump(says)));
}