2017-11-19 4 views
0

Ich habe die Klasse unten, die ich erstellt habe, um meine Zweifel zu veranschaulichen.Wie verschmelzen mehrere Objekte zu einem einzigen, nachdem die groupBy-Operation ausgeführt wurde?

Nach der anfänglichen Transformationen auf meinem fließfähig machen ich habe:

UserScoreTO{id=1, name='john', score=4} 
UserScoreTO{id=1, name='john', score=5} 
UserScoreTO{id=1, name='john', score=1} 
UserScoreTO{id=2, name='paul', score=4} 
UserScoreTO{id=2, name='paul', score=2} 
UserScoreTO{id=3, name='mark', score=1} 
UserScoreTO{id=3, name='mark', score=7} 

I UserScoreTO Objekte mit der gleichen ID in einem fließfähigen kombinieren möchten, die für jede Gruppe ein einzelnes Objekt aussendet, dass die Benutzerinformationen enthält und die Summe der Punkte.

So wird das Ergebnis fließfähig sein, das emittiert:

User (1, "john", 10); 
User (2, "paul", 6); 
User (3, "mark", 8); 

ich dies mit RxJava tun will, wenn möglich (ich weiß, ich gleiches Ergebnis etwas zu tun mit HashMaps erreichen konnte).

package examples.rxjava; 

import java.util.Arrays; 
import java.util.List; 

import io.reactivex.Flowable; 

import static java.lang.System.out; 

public class TestUsers { 

    public static void main(String[] args) { 
     new TestUsers().execute(); 
    } 


    public void execute() { 
     getUsers() 
       .flatMap(list -> Flowable.fromIterable(list)) 
       .groupBy(userScoreTO -> userScoreTO.id).subscribe(group -> group.subscribe(out::println)); 

    } 





    Flowable<List<UserScoreTO>> getUsers() { 
     return Flowable.fromCallable(
       () -> Arrays.asList(
         new UserScoreTO(1, "john", 4), 
         new UserScoreTO(1, "john", 5), 
         new UserScoreTO(1, "john", 1), 

         new UserScoreTO(2, "paul", 4), 
         new UserScoreTO(2, "paul", 2), 

         new UserScoreTO(3, "mark", 1), 
         new UserScoreTO(3, "mark", 7)) 
     ); 


    } 

    private class User { 
     private int id; 
     private String name; 
     private int totalScore; 

     public User(int id, String name, int totalScore) { 
      this.id = id; 
      this.name = name; 
      this.totalScore = totalScore; 
     } 

     @Override 
     public String toString() { 
      return "User{" + 
        "id=" + id + 
        ", name='" + name + '\'' + 
        ", totalScore=" + totalScore + 
        '}'; 
     } 
    } 

    private class UserScoreTO { 
     private int id; 
     private String name; 
     private int score; 


     public UserScoreTO(int id, String name, int score) { 
      this.id = id; 
      this.name = name; 
      this.score = score; 
     } 

     @Override 
     public String toString() { 
      return "UserScoreTO{" + 
        "id=" + id + 
        ", name='" + name + '\'' + 
        ", score=" + score + 
        '}'; 
     } 
    } 

} 

Antwort

1

Der von Ihnen bereitgestellte Code erfüllt genau das, was Sie wollen. groupBy gruppiert UserScoreTO-Objekte mit derselben ID in dasselbe GroupedFlowable-Objekt.

Edit:

Okay, ich sehe, vielleicht folgendes tut, was Sie ein bisschen besser wollen

public void execute() { 
getUsers() 
    .flatMap(Flowable::fromIterable) 
    .groupBy(userScoreTO -> userScoreTO.id) 
    .map(group -> group.reduce(new User(group.getKey(), "", 0), 
     (user, userScoreTO) -> { 
      user.name = userScoreTO.name; 
      user.totalScore += userScoreTO.score; 
      return user; 
     })) 
    .subscribe(userSingle -> userSingle.subscribe(System.out::println)); 

}

Was Sie wollen, ist die UserScoreTo in das gleiche aggregieren Benutzerobjekt durch Anwenden des Reduzierungsoperators.

+0

Es druckt das UserScoreTO gruppiert nach ID. Ich möchte diese Objekte in Benutzerobjekte umwandeln, wiederholtes UserScoreTO in ein User-Objekt zusammenführen und die Scores hinzufügen. Das erwartete Ergebnis wird im Text der Frage angezeigt. – alexpfx

1

Nach einigen Recherchen und viel Trial-and-Error-Code, fand ich diesen [collect][1] Operator, der Trick:

Es erstellt ein neues Objekt Benutzer (User::new) als Erstanbieter, die Daten hält aus allen Artikeln einer Gruppe. Also setze ich die Eigenschaften und inkrementiere die Punktzahl und gebe sie am Ende der Gruppeniteration zurück.

Wie ich bin neu in RxJava Ich weiß nicht, ob dies der beste Ansatz ist, oder wenn der Code vereinfacht werden kann, aber der resultierende Code ist:

getUsers() 
       .flatMap(list -> Flowable.fromIterable(list)) 
       .groupBy(userScoreTO -> userScoreTO.id) 
       .flatMap(groups -> Flowable.fromCallable(() -> groups.collect(User::new, (user, userscore) -> { 
        user.id = userscore.id; 
        user.name = userscore.name; 
        user.totalScore += userscore.score; 
       }))).subscribe(userSingle -> { 
      userSingle.subscribe(new SingleObserver<User>() { 
       @Override 
       public void onSubscribe(Disposable d) { 
        System.out.println("onSubscribe"); 
       } 

       @Override 
       public void onSuccess(User user) { 
        System.out.println(user); 
       } 

       @Override 
       public void onError(Throwable e) { 
        System.out.println(e); 

       } 
      }); 

     }); 

Der Ausgang:

onSubscribe 
onSubscribe 
onSubscribe 
User{id=1, name='john', totalScore=10} 
User{id=2, name='paul', totalScore=6} 
User{id=3, name='mark', totalScore=8} 
Verwandte Themen