Ich habe den Code zum Gruppieren der Objekte nach einem Feldnamen von POJO gefunden. Unten ist der Code dafür:
public class Temp {
static class Person {
private String name;
private int age;
private long salary;
Person(String name, int age, long salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
}
}
public static void main(String[] args) {
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);
}
}
Und die Ausgabe ist (was richtig ist):
{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}
Aber was ist, wenn ich nach mehreren Feldern gruppieren möchte? Ich kann natürlich einige POJO in der groupingBy()
Methode übergeben, nachdem ich die equals()
Methode in diesem POJO implementiert habe , aber gibt es eine andere Option, wie ich nach mehr als einem Feld aus dem angegebenen POJO gruppieren kann?
ZB hier in meinem Fall möchte ich nach Name und Alter gruppieren.
mapping
als nachgeschalteter Kollektor ist in dem von Ihnen geposteten Code redundant.people.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
.Antworten:
Sie haben hier einige Möglichkeiten. Am einfachsten ist es, Ihre Sammler zu verketten:
Um eine Liste von 18-jährigen Leuten namens Fred zu erhalten, würden Sie Folgendes verwenden:
map.get("Fred").get(18);
Eine zweite Option besteht darin, eine Klasse zu definieren, die die Gruppierung darstellt. Dies kann innerhalb der Person sein. Dieser Code verwendet a
record
, kann aber genauso gut eine Klasse (mitequals
undhashCode
definiert) in Java-Versionen sein, bevor JEP 359 hinzugefügt wurde:class Person { record NameAge(String name, int age) { } public NameAge getNameAge() { return new NameAge(name, age); } }
Dann können Sie verwenden:
und suchen mit
map.get(new NameAge("Fred", 18));
Wenn Sie keinen eigenen Gruppendatensatz implementieren möchten, haben viele der Java-Frameworks eine
pair
Klasse, die für diese Art von Dingen entwickelt wurde. Beispiel: Apache Commons-Paar Wenn Sie eine dieser Bibliotheken verwenden, können Sie den Schlüssel für die Karte zu einem Paar aus Name und Alter machen:und abrufen mit:
map.get(Pair.of("Fred", 18));
Persönlich sehe ich nicht viel Wert in generischen Tupeln, da Datensätze in der Sprache verfügbar sind, da Datensätze die Absicht besser anzeigen und sehr wenig Code erfordern.
quelle
Function<T,U>
verbirgt auch Absichten in diesem Sinne --- aber Sie werden niemanden sehen, der für jeden Mapping-Schritt seine eigene Funktionsschnittstelle deklariert; Die Absicht ist bereits im Lambda-Körper vorhanden. Gleiches gilt für Tupel: Sie eignen sich hervorragend als Klebetypen zwischen API-Komponenten. BTW Scala Fallklassen sind IMHO ein großer Gewinn sowohl in Bezug auf Prägnanz und Absicht Exposition.NameAge
als Einzeiler:case class NameAge { val name: String; val age: Int }
--- und Sie erhaltenequals
,hashCode
undtoString
!Map<String, Map<Integer, List<Person>>> map
Hier sehen Sie den Code:
Sie können einfach eine Funktion erstellen und sie die Arbeit für Sie erledigen lassen, eine Art funktionaler Stil!
Jetzt können Sie es als Karte verwenden:
Prost!
quelle
Die
groupingBy
Methode hat den ersten ParameterFunction<T,K>
:Wenn wir Lambda durch die anonyme Klasse in Ihrem Code ersetzen, können wir Folgendes sehen:
people.stream().collect(Collectors.groupingBy(new Function<Person, int>() { @Override public int apply(Person person) { return person.getAge(); } }));
Ändern Sie gerade den Ausgabeparameter
<K>
. In diesem Fall habe ich beispielsweise eine Paarklasse aus org.apache.commons.lang3.tuple zum Gruppieren nach Name und Alter verwendet. Sie können jedoch auch eine eigene Klasse zum Filtern von Gruppen nach Bedarf erstellen.people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() { @Override public YourFilter apply(Person person) { return Pair.of(person.getAge(), person.getName()); } }));
Nach dem Ersetzen durch Lambda sieht der Code schließlich so aus:
quelle
List<String>
?Hallo, Sie können einfach Ihre
groupingByKey
wie verkettenMap<String, List<Person>> peopleBySomeKey = people .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList()))); //write getGroupingByKey() function private String getGroupingByKey(Person p){ return p.getAge()+"-"+p.getName(); }
quelle
Sie können List als Klassifizierer für viele Felder verwenden, müssen jedoch Nullwerte in Optional umschließen:
quelle
Definieren Sie eine Klasse für die Schlüsseldefinition in Ihrer Gruppe.
class KeyObj { ArrayList<Object> keys; public KeyObj( Object... objs ) { keys = new ArrayList<Object>(); for (int i = 0; i < objs.length; i++) { keys.add( objs[i] ); } } // Add appropriate isEqual() ... you IDE should generate this }
Jetzt in Ihrem Code,
peopleByManyParams = people .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
quelle
Ararys.asList()
- was übrigens eine gute Wahl für den Fall von OP ist.Pair
im anderen Beispiel erwähnten Beispiel, jedoch ohne Argumentationsbeschränkung.hashCode
) einmal)Ich musste einen Bericht für eine Catering-Firma erstellen, die Mittagessen für verschiedene Kunden serviert. Mit anderen Worten, das Catering hat möglicherweise mehrere Firmen, die Bestellungen vom Catering entgegennehmen, und es muss wissen, wie viele Mittagessen es jeden Tag für alle Kunden produzieren muss!
Nur um zu bemerken, habe ich keine Sortierung verwendet, um dieses Beispiel nicht zu komplizieren.
Das ist mein Code:
@Test public void test_2() throws Exception { Firm catering = DS.firm().get(1); LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0); LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0); Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant()); Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant()); List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false); Map<Object, Long> M = LON.stream().collect( Collectors.groupingBy(p -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()), Collectors.counting())); for (Map.Entry<Object, Long> e : M.entrySet()) { Object key = e.getKey(); Long value = e.getValue(); System.err.println(String.format("Client firm :%s, total: %d", key, value)); } }
quelle
So habe ich nach mehreren Feldern branchCode und prdId gruppiert. Ich habe es nur für jemanden in Not gepostet
import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * * @author charudatta.joshi */ public class Product1 { public BigInteger branchCode; public BigInteger prdId; public String accountCode; public BigDecimal actualBalance; public BigDecimal sumActBal; public BigInteger countOfAccts; public Product1() { } public Product1(BigInteger branchCode, BigInteger prdId, String accountCode, BigDecimal actualBalance) { this.branchCode = branchCode; this.prdId = prdId; this.accountCode = accountCode; this.actualBalance = actualBalance; } public BigInteger getCountOfAccts() { return countOfAccts; } public void setCountOfAccts(BigInteger countOfAccts) { this.countOfAccts = countOfAccts; } public BigDecimal getSumActBal() { return sumActBal; } public void setSumActBal(BigDecimal sumActBal) { this.sumActBal = sumActBal; } public BigInteger getBranchCode() { return branchCode; } public void setBranchCode(BigInteger branchCode) { this.branchCode = branchCode; } public BigInteger getPrdId() { return prdId; } public void setPrdId(BigInteger prdId) { this.prdId = prdId; } public String getAccountCode() { return accountCode; } public void setAccountCode(String accountCode) { this.accountCode = accountCode; } public BigDecimal getActualBalance() { return actualBalance; } public void setActualBalance(BigDecimal actualBalance) { this.actualBalance = actualBalance; } @Override public String toString() { return "Product{" + "branchCode:" + branchCode + ", prdId:" + prdId + ", accountCode:" + accountCode + ", actualBalance:" + actualBalance + ", sumActBal:" + sumActBal + ", countOfAccts:" + countOfAccts + '}'; } public static void main(String[] args) { List<Product1> al = new ArrayList<Product1>(); System.out.println(al); al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "001", new BigDecimal("10"))); al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "002", new BigDecimal("10"))); al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "003", new BigDecimal("10"))); al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "004", new BigDecimal("10"))); al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "005", new BigDecimal("10"))); al.add(new Product1(new BigInteger("01"), new BigInteger("13"), "006", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "007", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "008", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "009", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "010", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "011", new BigDecimal("10"))); al.add(new Product1(new BigInteger("02"), new BigInteger("13"), "012", new BigDecimal("10"))); //Map<BigInteger, Long> counting = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.counting())); // System.out.println(counting); //group by branch code Map<BigInteger, List<Product1>> groupByBrCd = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.toList())); System.out.println("\n\n\n" + groupByBrCd); Map<BigInteger, List<Product1>> groupByPrId = null; // Create a final List to show for output containing one element of each group List<Product> finalOutputList = new LinkedList<Product>(); Product newPrd = null; // Iterate over resultant Map Of List Iterator<BigInteger> brItr = groupByBrCd.keySet().iterator(); Iterator<BigInteger> prdidItr = null; BigInteger brCode = null; BigInteger prdId = null; Map<BigInteger, List<Product>> tempMap = null; List<Product1> accListPerBr = null; List<Product1> accListPerBrPerPrd = null; Product1 tempPrd = null; Double sum = null; while (brItr.hasNext()) { brCode = brItr.next(); //get list per branch accListPerBr = groupByBrCd.get(brCode); // group by br wise product wise groupByPrId=accListPerBr.stream().collect(Collectors.groupingBy(Product1::getPrdId, Collectors.toList())); System.out.println("===================="); System.out.println(groupByPrId); prdidItr = groupByPrId.keySet().iterator(); while(prdidItr.hasNext()){ prdId=prdidItr.next(); // get list per brcode+product code accListPerBrPerPrd=groupByPrId.get(prdId); newPrd = new Product(); // Extract zeroth element to put in Output List to represent this group tempPrd = accListPerBrPerPrd.get(0); newPrd.setBranchCode(tempPrd.getBranchCode()); newPrd.setPrdId(tempPrd.getPrdId()); //Set accCOunt by using size of list of our group newPrd.setCountOfAccts(BigInteger.valueOf(accListPerBrPerPrd.size())); //Sum actual balance of our of list of our group sum = accListPerBrPerPrd.stream().filter(o -> o.getActualBalance() != null).mapToDouble(o -> o.getActualBalance().doubleValue()).sum(); newPrd.setSumActBal(BigDecimal.valueOf(sum)); // Add product element in final output list finalOutputList.add(newPrd); } } System.out.println("+++++++++++++++++++++++"); System.out.println(finalOutputList); } }
Die Ausgabe ist wie folgt:
+++++++++++++++++++++++ [Product{branchCode:1, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:1, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:1, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}, Product{branchCode:2, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:2, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:2, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}]
Nach dem Formatieren:
[ Product{branchCode:1, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:1, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:1, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}, Product{branchCode:2, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:2, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:2, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1} ]
quelle