获取过滤器索引的优雅方式或首先使用 RX Java

Elegant way to get index of filter or first with RX Java

我只是在练习 RX Java 并希望获得与过滤器匹配的项目在数组中的位置。我看不到任何明显的方法。我正在考虑压缩一个范围和可迭代的可观察对象或其他东西,但它很快变得比 for 循环更冗长和复杂。

RxJava 中曾经有 mapWithIndexzipWithIndex 运算符,但它们被删除了,请参阅 here 原因。

所以你必须写一次库样板:

class Indexed<T> {
    final int index;
    final T value;
    public Indexed(T value, int index) {
        this.index = index;
        this.value = value;
    }
    @Override
    public String toString() {
        return index + ") " + value;
    }
}

Iterable<Integer> naturals = IntStream.iterate(0, i -> i + 1)::iterator;

但是,你可以得到它相当简洁:

Observable<String> obs = Observable.just("zero", "one", "two", "three");
obs.zipWith(naturals, (s, i) -> new Indexed<String>(s, i))
   .filter(e -> e.value.length() > 4)
   .subscribe(System.out::println);

没有一种正确的方法可以做到这一点。塞缪尔的答案可以是一个。 它还取决于更大的图景,取决于您的数组是什么以及您需要如何处理订阅者中的结果。

这是一个 (java7) 示例,其中 Observer 发出 ArrayList<String>:

strings.map(new Func1<ArrayList<String>, ArrayList<Integer>>() {
            @Override
            public ArrayList<Integer> call(ArrayList<String> strings) {
                ArrayList<Integer> list = new ArrayList<>();
                for(String string: strings){
                    if(statement){
                        list.add(strings.indexOf(string));
                    }
                }
                return list;
            }
        }).subscribe(new Action1<ArrayList<Integer>>() {
            @Override
            public void call(ArrayList<Integer> integers) {
                doSomethingWithThePositions(integers);
            }
        });

这是一个示例,其中 Observer 每次从您的 ArrayList 发出 String

final ArrayList<String> strings1 = new ArrayList<>();
Observable.from(strings1)
        .filter(new Func1<String, Boolean>() {
            @Override
            public Boolean call(String s) {
                return !s.isEmpty();
            }
        })
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                int i = strings1.indexOf(s);
                doSomethingWithThePosition(i);
            }
        });

我喜欢塞缪尔的回答。我已经为他的东西编写了一个 Transformer 实现,它符合 Java 6/7 并使用长索引(我有很长的流要处理!)。

你这样称呼它:

Observable.just("a", "b").compose(MapWithIndex.<String>instance());

这是 class(源代码和单元测试 here):

package com.github.davidmoten.util;

import java.util.Iterator;

import rx.Observable;
import rx.Observable.Transformer;
import rx.functions.Func2;

import com.github.davidmoten.util.MapWithIndex.Indexed;

public final class MapWithIndex<T> implements Transformer<T, Indexed<T>> {

    private static class Holder {
        static final MapWithIndex<?> INSTANCE = new MapWithIndex<Object>();
    }

    @SuppressWarnings("unchecked")
    public static <T> MapWithIndex<T> instance() {
        return (MapWithIndex<T>) Holder.INSTANCE;
    }

    @Override
    public Observable<Indexed<T>> call(Observable<T> source) {

        return source.zipWith(NaturalNumbers.instance(), new Func2<T, Long, Indexed<T>>() {

            @Override
            public Indexed<T> call(T t, Long n) {
                return new Indexed<T>(t, n);
            }
        });
    }

    public static class Indexed<T> {
        private final long index;
        private final T value;

        public Indexed(T value, long index) {
            this.index = index;
            this.value = value;
        }

        @Override
        public String toString() {
            return index + "->" + value;
        }

        public long index() {
            return index;
        }

        public T value() {
            return value;
        }

    }

    private static final class NaturalNumbers implements Iterable<Long> {

        private static class Holder {
            static final NaturalNumbers INSTANCE = new NaturalNumbers();
        }

        static NaturalNumbers instance() {
            return Holder.INSTANCE;
        }

        @Override
        public Iterator<Long> iterator() {
            return new Iterator<Long>() {

                private long n = 0;

                @Override
                public boolean hasNext() {
                    return true;
                }

                @Override
                public Long next() {
                    return n++;
                }

                @Override
                public void remove() {
                    throw new RuntimeException("not supported");
                }
            };
        }

    }

}