获取过滤器索引的优雅方式或首先使用 RX Java
Elegant way to get index of filter or first with RX Java
我只是在练习 RX Java 并希望获得与过滤器匹配的项目在数组中的位置。我看不到任何明显的方法。我正在考虑压缩一个范围和可迭代的可观察对象或其他东西,但它很快变得比 for 循环更冗长和复杂。
RxJava 中曾经有 mapWithIndex
和 zipWithIndex
运算符,但它们被删除了,请参阅 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");
}
};
}
}
}
我只是在练习 RX Java 并希望获得与过滤器匹配的项目在数组中的位置。我看不到任何明显的方法。我正在考虑压缩一个范围和可迭代的可观察对象或其他东西,但它很快变得比 for 循环更冗长和复杂。
RxJava 中曾经有 mapWithIndex
和 zipWithIndex
运算符,但它们被删除了,请参阅 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"); } }; } } }