2

I have a code flow that generates an Iterable of Observables of the same type. I then go through them all, combining them and returning the result as an Observable. At the moment I'm using zip with a FuncN, which seems horrible and I think I've missed the point somewhere. Here's an example that uses a Map, it's obviously nonsense but you get the idea.

final ImmutableList.Builder<Map<String, Object>> observables = 
        ImmutableList.builder();
for (String key: keys) {
    if (someTest(key)) {
        observables.add(generateObservableMap(key));
    }
}

return Observable.zip(observables.build(), data -> {
    final Map<String, Object> result = Maps.newHashMap();

    // THIS IS REALLY UGLY
    for (Object d: data) {
        for (Object e: ((Map) d).entrySet()) {
            final Map.Entry entry = (Map.Entry) e;
            final String key = (Model) entry.getKey();
            final Object value = (AuthData) entry.getValue();
            result.put(key, value);
        }
    }

    return ImmutableMap.copyOf(result);
});

I'm sure there's a better way of doing this.

Ben Smith
  • 1,554
  • 1
  • 15
  • 26
  • 1
    So you have an Observable>> and want to transform that to an Observable> by combining all the maps to one bigger map, right? Did you have a look at `reduce` - it corresponds to fold in some functional programming languages and seems to fit quite well: you start with an empty map and then in each step add the items of the next map to that map. – david.mihola Oct 01 '14 at 07:09
  • 1
    Sorry I just saw that you are starting with an Iterable>> instead of an Observable<...> - but it can easily transformed with `Observable.from`. – david.mihola Oct 01 '14 at 07:11

1 Answers1

0

This is actually more a question about Java Collections than about RxJava. The part that you labelled as REALLY UGLY can be made a bit nicer using putAll:

@SuppressWarnings("unchecked")
public static <K, V> Map<K, V> mergeMaps(Object... maps) {
    final Map<K, V> result = new HashMap<K, V>();
    for (Object map: maps) {
        // unchecked <K,V> require @SuppressWarnings
        result.putAll((Map<K,V>)map);
    }
    return result;
}

Notice that if the same key occurs in several maps, only the last value for it will be in the result.

You may wonder why I chose Object... as argument type instead of Map<K,V>.... The reason is that FuncN will have an Object[], which cannot be cast to a Map<K,V>[], because this would throw a ClassCastException, even if all elements in the array are of type Map.

Now if you have some sampleObservables inside an Iterable<Observable<Map<String, Object>>>, you can use zip and mergeMaps as follows:

return Observable.zip(sampleObservables, new FuncN<Map<String, Object>>() {
    public Map<String, Object> call(Object... args) {
        return mergeMaps(args);
    }
});
Samuel Gruetter
  • 1,713
  • 12
  • 11