J'ai trouvé le code pour regrouper les objets par un nom de champ de POJO. Voici le code pour cela:
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);
}
}
Et la sortie est (ce qui est correct):
{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}]}
Mais que faire si je souhaite regrouper par plusieurs champs? Je peux évidemment passer un POJO dans la groupingBy()
méthode après avoir implémenté la equals()
méthode dans ce POJO mais y a-t-il une autre option comme je peux grouper par plus d'un champs du POJO donné?
Par exemple, dans mon cas, je souhaite regrouper par nom et par âge.
mapping
tant que collecteur en aval est redondant dans le code que vous avez publié.people.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
.Réponses:
Vous avez ici quelques options. Le plus simple est d'enchaîner vos collectionneurs:
Ensuite, pour obtenir une liste de personnes de 18 ans appelées Fred, vous utiliseriez:
map.get("Fred").get(18);
Une deuxième option consiste à définir une classe qui représente le regroupement. Cela peut être à l'intérieur de Person. Ce code utilise a
record
mais il pourrait tout aussi bien être une classe (avecequals
ethashCode
définie) dans les versions de Java avant l'ajout de JEP 359:class Person { record NameAge(String name, int age) { } public NameAge getNameAge() { return new NameAge(name, age); } }
Ensuite, vous pouvez utiliser:
et recherchez avec
map.get(new NameAge("Fred", 18));
Enfin, si vous ne souhaitez pas implémenter votre propre enregistrement de groupe, de nombreux frameworks Java ont une
pair
classe conçue pour ce type de chose. Par exemple: apache commons pair Si vous utilisez l'une de ces bibliothèques, vous pouvez attribuer à la clé de la carte une paire du nom et de l'âge:et récupérez avec:
map.get(Pair.of("Fred", 18));
Personnellement, je ne vois pas vraiment beaucoup de valeur dans les tuples génériques maintenant que les enregistrements sont disponibles dans la langue car les enregistrements affichent mieux l'intention et nécessitent très peu de code.
la source
Function<T,U>
cache également l'intention dans ce sens --- mais vous ne verrez personne déclarer sa propre interface fonctionnelle pour chaque étape de mappage; l'intention est déjà là dans le corps lambda. Idem avec les tuples: ils sont parfaits comme types de colle entre les composants d'API. Les classes de cas de BTW Scala sont à mon humble avis une grande victoire en termes de concision et d'exposition intentionnelle.NameAge
comme un paquebot:case class NameAge { val name: String; val age: Int }
--- et vous obtenezequals
,hashCode
ettoString
!Map<String, Map<Integer, List<Person>>> map
Regardez ici le code:
Vous pouvez simplement créer une fonction et la laisser faire le travail pour vous, une sorte de style fonctionnel!
Vous pouvez maintenant l'utiliser comme carte:
À votre santé!
la source
La
groupingBy
méthode a le premier paramètre estFunction<T,K>
où:Si nous remplaçons lambda par la classe anonyme dans votre code, nous pouvons voir une sorte de cela:
people.stream().collect(Collectors.groupingBy(new Function<Person, int>() { @Override public int apply(Person person) { return person.getAge(); } }));
Modifiez maintenant le paramètre de sortie
<K>
. Dans ce cas, par exemple, j'ai utilisé une classe de paires de org.apache.commons.lang3.tuple pour le regroupement par nom et âge, mais vous pouvez créer votre propre classe pour filtrer les groupes selon vos besoins.people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() { @Override public YourFilter apply(Person person) { return Pair.of(person.getAge(), person.getName()); } }));
Enfin, après avoir remplacé par lambda back, le code ressemble à ça:
la source
List<String>
?Salut, vous pouvez simplement concaténer votre
groupingByKey
tel queMap<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(); }
la source
Définissez une classe pour la définition de clé dans votre groupe.
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 }
Maintenant dans votre code,
peopleByManyParams = people .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
la source
Ararys.asList()
--- ce qui est BTW un bon choix pour le cas d'OP.Pair
exemple mentionné dans l'autre exemple, mais sans limite d'argument.hashCode
) une fois)Vous pouvez utiliser List comme classificateur pour de nombreux champs, mais vous devez encapsuler les valeurs nulles dans Facultatif:
la source
J'avais besoin de faire rapport pour une entreprise de restauration qui sert des déjeuners pour divers clients. En d'autres termes, la restauration peut avoir une ou plusieurs entreprises qui prennent les commandes de la restauration, et elle doit savoir combien de déjeuners elle doit produire chaque jour pour tous ses clients!
Juste pour remarquer, je n'ai pas utilisé le tri, afin de ne pas trop compliquer cet exemple.
Voici mon 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)); } }
la source
C'est ainsi que j'ai fait le regroupement par plusieurs champs branchCode et prdId, il suffit de le poster pour quelqu'un dans le besoin
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); } }
La sortie est comme ci-dessous:
+++++++++++++++++++++++ [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}]
Après l'avoir formaté:
[ 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} ]
la source