2016-07-19 9 views
-1

Ich bekomme eine Arraylist von Objekten dieser Klasse. z.B .:java 8 groupBY oder mit allgemeinen Ansatz

new Foo(1, "P1", 300, 400), 
new Foo(1, "P4", 300, 400), 
new Foo(2, "P2", 600, 400), 
new Foo(3, "P3", 30, 20), 
new Foo(3, "P3", 70, 20), 
new Foo(1, "P1", 360, 40), 
new Foo(4, "P4", 320, 200), 
new Foo(4, "P4", 500, 900) 

Ich möchte diese Werte zu transformieren, indem eine neue Liste von FOO Objekt mit Summenwert sowohl von id und Referenz gruppiert zu schaffen. es sein wird, wie:

new Foo(1, "P1", 660, 440), 
new Foo(1, "P4", 300, 400), 
new Foo(2, "P2", 600, 400), 
new Foo(3, "P3", 100, 40) 
+1

Bitte lesen Sie http://stackoverflow.com/help/how-to-ask. Es wird Ihnen helfen, Ihre Frage so zu formulieren, dass wir Ihnen helfen können. – jbrown

+0

@jbrown Er möchte eine Methode, die eine 'ArrayList' von' Foo's akzeptiert und die gruppierte Version dieser 'ArrayList' zurückgibt. Beispiel: Iterieren Sie alle Elemente der Liste, überprüfen Sie, ob das Element bereits in der Liste vorhanden ist, die zurückgegeben wird, wenn es dann nicht hinzugefügt wird, wenn es die numerischen Werte zusammenführt. –

+0

@nickzoum - nur die Idee von "Enthalten gerade genug Code, um anderen zu ermöglichen, das Problem zu reproduzieren" wie im verknüpften Dokument erläutert – jbrown

Antwort

-1

eine Methode wie diese verwendet, die jedes Element aus der ersten Liste erhalten werden, überprüft, ob es in der neuen Liste vorhanden ist, wenn es nicht das es kommt noch hinzu, um das Element der neue Liste Wenn dies der Fall ist, fügt es die zwei letzten Felder des Elements zu dem Element mit denselben ersten zwei Feldern hinzu, die in der Liste vorhanden sind.

public ArrayList<Foo> groupList(ArrayList<Foo> list){ 
    ArrayList<Foo> foos = new ArrayList<Foo>(); 
    for(Foo foo: list){ 
     Foo temp = getFoo(foos, foo); 
     if(temp != null){ 
      temp.merge(foo); 
     }else{ 
      foos.add(foo); 
     } 
    } 
} 

public Foo getFoo(ArrayList<Foo> foos, Foo foo){ 
    for(Foo temp: foos){ 
     if(foos.equals(temp)){ 
      return temp; 
     } 
    } 
    return null; 
} 

Und fügen Sie diese Methoden zu Ihrer Foo Klasse hinzu. Diese gehen davon aus, dass die Felder von Foobar1 genannt werden, bar2, bar3 und bar4

public void merge(Foo otherFoo){ 
    this.setBar3(this.getBar3 + otherFoo.getBar3); 
    this.setBar4(this.getBar4 + otherFoo.getBar4); 
} 

public boolean equals(Object object){ 
    if(object instanceof Foo){ 
     Foo otherFoo = (Foo)object; 
     if(getBar1.equals(otherFoo.getBar1) && getBar2.equals(otherFoo.getBar2)){ 
      return true; 
     } 
    } 
    return false; 
} 
0

Wenn Ihre Absicht, eine solche „besondere“ Gruppierung zu tun ist, sollten Sie (oder besser gesagt: kann) nicht den eingebauten verwenden in groupBy Funktion. Die Semantik der integrierten Funktion enthält nicht die Operation "Zusammenführen", die Sie für die Objekte Foo ausführen möchten.

Stattdessen können Sie die Collectors#toMap Funktion:

  • Die keyMapper ist eine Funktion, die einen Schlüssel, eine Art von „Kennung“ für die Einträge erstellt. In Ihrem Fall ist dies eine Funktion, die eine Foo übernimmt und ein Objekt Entry<Integer, String> erstellt, das als Schlüssel für die Karte verwendet wird. (Sie jede Pair oder Tuple es verwenden könnte - auch ein List<Object> es tun würde)
  • Die valueMapper kann die Identitätsfunktion
  • Die mergeFunction ist wichtig hier: Es dauert zwei Foo Objekte (mit der gleichen Anzahl und String) und gibt ein neues, verschmolzenes Objekt Foo zurück, in dem die restlichen Werte hinzugefügt wurden.

Das Ergebnis wird ein Map sein, aber Sie können einen List aus den Werten dieser Karte erstellen, falls gewünscht.

Hier ein Beispiel:

import static java.util.stream.Collectors.toMap; 

import java.util.AbstractMap.SimpleEntry; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.function.BinaryOperator; 
import java.util.function.Function; 
import java.util.stream.Collectors; 

public class GroupByTest 
{ 
    public static void main(String[] args) 
    { 
     example(); 
     exampleUnmaintainable(); 
    } 


    private static void example() 
    { 
     List<Foo> foos = Arrays.asList(
      new Foo(1, "P1", 300, 400), 
      new Foo(1, "P4", 300, 400), 
      new Foo(2, "P2", 600, 400), 
      new Foo(3, "P3", 30, 20), 
      new Foo(3, "P3", 70, 20), 
      new Foo(1, "P1", 360, 40), 
      new Foo(4, "P4", 320, 200), 
      new Foo(4, "P4", 500, 900) 
     ); 

     Function<Foo, Entry<Integer, String>> keyMapper = foo -> 
      new SimpleEntry<Integer, String>(foo.getId(), foo.getS()); 
     Function<Foo, Foo> valueMapper = foo -> foo; 
     BinaryOperator<Foo> mergeFunction = (f0, f1) -> 
      new Foo(f0.getId(), f0.getS(), f0.getX()+f1.getX(), f0.getY()+f1.getY()); 
     Map<Entry<Integer, String>, Foo> result = 
      foos.stream().collect(toMap(keyMapper, valueMapper, mergeFunction)); 

     for (Entry<Entry<Integer, String>, Foo> entry : result.entrySet()) 
     { 
      System.out.println(entry); 
     } 
    } 


    private static void exampleUnmaintainable() 
    { 
     List<Foo> foos = Arrays.asList(
      new Foo(1, "P1", 300, 400), 
      new Foo(1, "P4", 300, 400), 
      new Foo(2, "P2", 600, 400), 
      new Foo(3, "P3", 30, 20), 
      new Foo(3, "P3", 70, 20), 
      new Foo(1, "P1", 360, 40), 
      new Foo(4, "P4", 320, 200), 
      new Foo(4, "P4", 500, 900) 
     ); 

     List<Foo> result = foos.stream().collect(toMap(
      foo -> new SimpleEntry<Integer, String>(foo.getId(), foo.getS()), 
      foo -> foo, (f0, f1) -> new Foo(f0.getId(), f0.getS(), 
       f0.getX()+f1.getX(), f0.getY()+f1.getY()))) 
      .values().stream().collect(Collectors.toList()); 

     for (Foo foo : result) 
     { 
      System.out.println(foo); 
     } 
    } 


    static class Foo 
    { 
     private int id; 
     private String s; 
     private int x; 
     private int y; 

     public Foo(int id, String s, int x, int y) 
     { 
      this.id = id; 
      this.s = s; 
      this.x = x; 
      this.y = y; 
     } 

     public int getId() 
     { 
      return id; 
     } 

     public String getS() 
     { 
      return s; 
     } 

     public int getX() 
     { 
      return x; 
     } 

     public int getY() 
     { 
      return y; 
     } 

     @Override 
     public String toString() 
     { 
      return "Foo [id=" + id + ", s=" + s + ", x=" + x + ", y=" + y + "]"; 
     } 
    } 

} 

Ja, eine passiv-aggressive Bemerkung: Wenn Sie die Methodennamen usw. nicht mögen, dann sollten Sie uns Ihre aktuelle Foo Klasse gezeigt haben. Wir haben, um ein bisschen hier zu raten ...

Verwandte Themen