Сопоставление двух неупорядоченных потоков по свойству, RxJava, RxAndroid

#java #android #rx-java

#java #Android #rx-java

Вопрос:

Наличие двух потоков, подобных следующему

 Stream 1: A -- B -- C -- D
Stream 2: 3 -- 1 -- 2 -- 4
  

Я хотел бы вывести

 Output: A1 -- B2 -- C3 -- D4
  

или

 Output: 3C -- 2B -- 1A -- 4D
  

Где каждая буква сопоставляется с ее положением в алфавите.
Я пробовал использовать операторы .zip и .combineLatest , но не получил нужного результата.

На самом деле это упрощение моей проблемы, на самом деле. A, B и C — это объекты, которые имеют свойства типа 1,2 или 3. Итак, я могу сделать что-то вроде A.position() = 1

Есть ли оператор, который конкретно решает мою проблему, или мне придется использовать хэш-карту и сопоставлять эти объекты самостоятельно?

Заранее спасибо.

Комментарии:

1. что такое операторы .zip и .cimbineLatest?

2. они являются реактивными операторами reactivex.io

3. Спасибо за простую абстракцию вашей проблемы в вопросе, это вносит приятные изменения! Интересная проблема, кстати, особенно для обработки бесконечных потоков и хорошей обработки противодавления (возможно, не ваш вариант использования, но все равно интересно).

4. В вашем втором варианте вывода 1A должно быть перед 2B

Ответ №1:

Используйте Observable.toSortedList , как показано ниже:

 Observable<Data> s1 = Observable.from(new Data[]{new Data(3), new Data(1), new Data(2), new Data(4)});
Observable<String> s2 = Observable.from(new String[]{"A", "B", "C", "D"});

Observable.zip(
        s1.toSortedList(this::compare).flatMap(Observable::from),
        s2,
        (d, s) -> s   d.number
).subscribe(s -> {
    //Output: A1 -- B2 -- C3 -- D4
});
  

compare способ:

 private Integer compare(Data a, Data b) {
    return a.number.equals(b.number) ? 0 : (a.number < b.number ? -1 : 1);
}
  

Data класс:

 class Data {
    private final Integer number;

    Data(Integer number) {
        this.number = number;
    }
}
  

Комментарии:

1. Возможно, я выбрал плохой пример в своем ответе, но «toSortedList» не сработал бы для моей версии, поток s1 содержит объекты с идентификаторами, а не числами. Я перепишу свой ответ, чтобы сделать его более общим.

Ответ №2:

я бы попробовал что-то вроде .flatMap() в одном потоке с .groupBy (ключ) в другом потоке, который будет выдавать Observable<GroupedObservable<YourType>>

или иным образом используйте .toMap() или .toMultimap() в другом потоке, который создаст наблюдаемые<Map<K,Collection<T>>>

не уверен, ожидаете ли вы определенного порядка

Ответ №3:

Вы можете использовать модульно протестированный оператор match из rxjava-extras 0.8.0.3 (или более поздней версии, если она доступна). Артефакт опубликован на Maven Central.

Добавьте это в свой pom.xml:

 <dependency>
  <groupId>com.github.davidmoten</groupId>
  <artifactId>rxjava-extras</artifactId>
  <version>0.8.0.3</version>
</dependency>
  

Пример:

 Observable<Integer> a = Observable.just(1, 2, 4, 3);
Observable<Integer> b = Observable.just(1, 2, 3, 5, 6, 4);
Obs.match(a, b,
     x -> x, // key to match on for a
     x -> x, // key to match on for b
     (x, y) -> x // combiner
    )
   .forEach(System.out::println);
  

Вывод:

 1
2
4
3
  

Комментарии:

1. Пожалуйста, обратите внимание, что я просто завершаю модульное тестирование оператора match в rxjava-extras. Приведенный выше алгоритм не обрабатывает повторы должным образом. Я дам вам знать, когда буду готов, выйдет в ближайшие пару дней.

2. заменил мой ответ недавно написанным оператором. Дайте мне знать, если возникнут какие-либо проблемы (предпочтительно как проблема в rxjava-extras на github).