2016-04-27 4 views
0

Je veux changer une liste à la liste, puis mapper en tant que carte. La clé serait "img" + index, comment puis-je le faire.comment obtenir l'index avec toMap() dans rxjava

exemple: de la liste [ "a", "b", "c"] à la carte { "img1": "a", "img2": "b", "img3": "c"}

Observable.from((Bitmap[])bitmapList.toArray()) 
      .subscribeOn(Schedulers.io()) 
      .map(new Func1<Bitmap, String>() { 
       @Override 
       public String call(Bitmap bitmap) { 
        return doSomething(bitmap); 
       } 
      }) 
      .toMap(new Func1<String, String>() { 
       @Override 
       public String call(String s) { 
        return "img"; // how to got the index 
       } 
      }) 
      ...; 
+0

Veuillez être précis avec votre question. Par exemple, vous pouvez demander l'erreur ou quelque chose sur votre code affiché –

+0

Je veux connaître l'index de la liste dans la fonction toMap(). – 0Kai

Répondre

2

afin de combiner une valeur avec un indice dont vous avez besoin un état interne: vous avez besoin de garder une trace d'un compteur dans le flux. Vous pouvez le faire avec l'opérateur scan. Parce que vous avez besoin de garder une trace des deux que le compteur et la valeur réelle, nous avons d'abord besoin d'introduire une classe simple qui peut contenir deux valeurs:

private static class Tuple<T, S> { 

    final T first; 
    final S second; 

    Tuple(T k, S v) { 
     this.first = k; 
     this.second = v; 
    } 
} 

L'opérateur scan nécessite deux paramètres: une valeur initiale pour la état et une fonction accumulateur qui prend l'état précédent et une nouvelle valeur et les transforme en un nouvel état. L'état initial est simple, c'est la combinaison de la chaîne vide ("") et d'un index initial (en fonction de l'index que vous voulez démarrer, 0 ou 1) L'accumulateur est facile maintenant: il prend la nouvelle valeur et incrémente le compteur de l'état précédent et les combine dans une nouvelle Tuple.

Parce que l'état initial n'est pas ce que vous voulez voir, vous devez faire un skip(1) pour se débarrasser du premier élément émis.

Enfin, vous peut faire toMap, mais vous devez prendre la version avec deux arguments: le keySelector et le valueSelector où vous obtenez la clé et la valeur de la Tuple respectivement.

Le code final se présente comme suit:

public static void main(String[] args) { 
    Observable.from(Arrays.asList("a", "b", "c")) 
      .scan(new Tuple<>("", 0), (tuple, s) -> new Tuple<>(s, tuple.second + 1)) 
      .skip(1) 
      .toMap(tuple -> "img" + tuple.second, tuple -> tuple.first) 
      .subscribe(System.out::println); 
} 

Notez que cette combinaison de scan et skip est en fait un zipWithIndex, comme on l'appelle par exemple dans RxScala. Java n'a pas de tuples dans la langue, donc vous ne pouvez pas le faire directement, mais vous devez créer votre propre classe Tuple pour que cela fonctionne.

+0

zipAvec (Observable.range (0, longueur), ...) pour lier Tuple peut-être mieux que sacn()? – 0Kai

+0

Absolument, c'est une solution parfaite pour ce cas particulier. Cependant, cela ne fonctionnera pas sur n'importe quel 'Observable' arbitraire (disons contenir des mouvements de souris) parce que vous ne savez pas quand les événements' onNext' arrivent et combien il y en aura. J'ai supposé que votre source était juste un mannequin et que vous le vouliez pour n'importe quel flux arbitraire dont la longueur n'est pas connue immédiatement. – RvanHeest

+0

peut-être que c'est une solution, mais je veux trouver une réponse sans le tuple. Merci ~ – 0Kai