Saya menemukan kode untuk mengelompokkan objek dengan beberapa nama bidang dari POJO. Di bawah ini adalah kode untuk itu:
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);
}
}
Dan hasilnya adalah (yang benar):
{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}]}
Tetapi bagaimana jika saya ingin mengelompokkan menurut beberapa bidang? Saya jelas dapat melewatkan beberapa POJO dalam groupingBy()
metode setelah menerapkan equals()
metode dalam POJO itu tetapi apakah ada opsi lain seperti saya dapat mengelompokkan berdasarkan lebih dari satu bidang dari POJO yang diberikan?
Misalnya di sini dalam kasus saya, saya ingin mengelompokkan berdasarkan nama dan usia.
mapping
sebagai kolektor hilir berlebihan dalam kode yang telah Anda posting.people.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
.Jawaban:
Anda memiliki beberapa opsi di sini. Yang paling sederhana adalah dengan mengikat kolektor Anda:
Kemudian untuk mendapatkan daftar orang berusia 18 tahun bernama Fred Anda akan menggunakan:
map.get("Fred").get(18);
Pilihan kedua adalah mendefinisikan kelas yang mewakili pengelompokan. Ini bisa di dalam Person. Kode ini menggunakan
record
tetapi bisa juga dengan mudah menjadi kelas (denganequals
danhashCode
ditentukan) dalam versi Java sebelum JEP 359 ditambahkan:class Person { record NameAge(String name, int age) { } public NameAge getNameAge() { return new NameAge(name, age); } }
Kemudian Anda dapat menggunakan:
dan telusuri dengan
map.get(new NameAge("Fred", 18));
Akhirnya jika Anda tidak ingin mengimplementasikan rekaman grup Anda sendiri, maka banyak kerangka kerja Java yang memiliki
pair
kelas yang dirancang untuk jenis hal ini. Sebagai contoh: pasangan apache commons Jika Anda menggunakan salah satu dari perpustakaan ini maka Anda dapat membuat kunci untuk peta sepasang nama dan umur:dan ambil dengan:
map.get(Pair.of("Fred", 18));
Secara pribadi saya tidak benar-benar melihat banyak nilai dalam tupel generik sekarang karena catatan tersedia dalam bahasa karena catatan menampilkan maksud lebih baik dan memerlukan sedikit kode.
sumber
Function<T,U>
juga menyembunyikan maksud dalam pengertian ini --- tetapi Anda tidak akan melihat siapa pun yang mendeklarasikan antarmuka fungsional mereka sendiri untuk setiap langkah pemetaan; maksudnya sudah ada di tubuh lambda. Sama dengan tupel: mereka bagus sebagai tipe perekat antar komponen API. Kelas kasus BTW Scala adalah IMHO kemenangan besar dalam hal keringkasan dan eksposur niat.NameAge
sebagai satu-kapal:case class NameAge { val name: String; val age: Int }
--- dan Anda mendapatkanequals
,hashCode
dantoString
!Map<String, Map<Integer, List<Person>>> map
Berikut lihat kodenya:
Anda cukup membuat Fungsi dan membiarkannya bekerja untuk Anda, semacam Gaya fungsional!
Sekarang Anda dapat menggunakannya sebagai peta:
Bersulang!
sumber
The
groupingBy
Metode telah parameter pertama adalahFunction<T,K>
di mana:Jika kami mengganti lambda dengan kelas anonim di kode Anda, kami dapat melihat beberapa jenis itu:
people.stream().collect(Collectors.groupingBy(new Function<Person, int>() { @Override public int apply(Person person) { return person.getAge(); } }));
Sekarang ubah parameter keluaran
<K>
. Dalam kasus ini, misalnya, saya menggunakan kelas pasangan dari org.apache.commons.lang3.tuple untuk pengelompokan menurut nama dan usia, tetapi Anda dapat membuat kelas Anda sendiri untuk memfilter grup sesuai kebutuhan.people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() { @Override public YourFilter apply(Person person) { return Pair.of(person.getAge(), person.getName()); } }));
Akhirnya, setelah mengganti dengan lambda back, kode terlihat seperti itu:
sumber
List<String>
?Hai, Anda cukup menggabungkan
groupingByKey
sepertiMap<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(); }
sumber
Tentukan kelas untuk definisi kunci dalam grup Anda.
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 }
Sekarang dalam kode Anda,
peopleByManyParams = people .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
sumber
Ararys.asList()
--- yang BTW adalah pilihan yang bagus untuk kasus OP.Pair
contoh yang disebutkan dalam contoh lain, tetapi tanpa batasan argumen.hashCode
) sekali)Anda dapat menggunakan Daftar sebagai pengklasifikasi untuk banyak bidang, tetapi Anda perlu menggabungkan nilai null ke dalam Opsional:
sumber
Saya perlu membuat laporan untuk perusahaan katering yang menyajikan makan siang untuk berbagai klien. Dengan kata lain, katering mungkin memiliki atau lebih banyak perusahaan yang menerima pesanan dari katering, dan harus tahu berapa banyak makan siang yang harus diproduksi setiap hari untuk semua kliennya!
Sekadar perhatikan, saya tidak menggunakan penyortiran, agar tidak terlalu memperumit contoh ini.
Ini kode saya:
@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)); } }
sumber
Ini adalah bagaimana saya melakukan pengelompokan berdasarkan beberapa bidang branchCode dan prdId, Hanya mempostingnya untuk seseorang yang membutuhkan
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); } }
Outputnya seperti di bawah ini:
+++++++++++++++++++++++ [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}]
Setelah Memformatnya:
[ 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} ]
sumber