Java Academy · Oppitunti

partitioningBy ja counting

Jaa stream kahdeksi ryhmäksi partitioningBy-metodilla ja laske alkiot counting-metodilla.

Oppitunti 2/413 vaihetta

partitioningBy ja counting on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

partitioningByn perusteet

Collectors.partitioningBy(predicate) jakaa streamin täsmälleen kahteen ryhmään — true ja false — ja palauttaa Map<Boolean, List<T>>-rakenteen.

import java.util.*;
import java.util.stream.*;

List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);

Map<Boolean, List<Integer>> evenOdd =
    nums.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));

System.out.println(evenOdd.get(true));  // [2, 4, 6, 8, 10]
System.out.println(evenOdd.get(false)); // [1, 3, 5, 7, 9]

partitioningBy ja filter

Toisin kuin filter, partitioningBy säilyttää molemmat ryhmät samanaikaisesti. Tämä on hyödyllistä, kun tarvitsette osituksen molemmat puolet.

record Student(String name, int score) {}
List<Student> students = List.of(
    new Student("Alice",90), new Student("Bob",55),
    new Student("Carol",72), new Student("Dave",48)
);

Map<Boolean, List<Student>> result =
    students.stream().collect(
        Collectors.partitioningBy(s -> s.score() >= 60)
    );
System.out.println("Passed: " + result.get(true).size());
System.out.println("Failed: " + result.get(false).size());

Downstream partitioningByn kanssa

Yhdistäkää partitioningBy downstream-kerääjään samalla tavalla kuin groupingBy:

Map<Boolean, Long> passFailCount =
    students.stream().collect(
        Collectors.partitioningBy(
            s -> s.score() >= 60,
            Collectors.counting()
        )
    );
System.out.println("Passed: " + passFailCount.get(true));
System.out.println("Failed: " + passFailCount.get(false));

counting()-kerääjä

Collectors.counting() laskee streamin (tai downstream-ryhmän) alkioiden määrän. Se on kätevä vastine lausekkeelle reducing(0L, e -> 1L, Long::sum).

long count = Stream.of("a","bb","ccc","dddd")
    .collect(Collectors.counting());
System.out.println(count); // 4

// Same as:
long count2 = Stream.of("a","bb","ccc","dddd").count();
// Use counting() as a downstream; use .count() as a terminal op

counting() downstream-kerääjänä

counting() on erityisen hyödyllinen groupingBy- ja partitioningBy-operaatioiden downstream-kerääjänä:

List<String> words = List.of("cat","dog","car","door","cup","dune");

Map<Character, Long> byFirstLetter =
    words.stream().collect(
        Collectors.groupingBy(w -> w.charAt(0), Collectors.counting())
    );
byFirstLetter.forEach((c, n) -> System.out.println(c + ": " + n));
// c: 3, d: 3

Osittelu nimien perusteella

Poimikaa nimet kustakin osituksesta mapping-downstream-kerääjän avulla:

Map<Boolean, List<String>> namesByPass =
    students.stream().collect(
        Collectors.partitioningBy(
            s -> s.score() >= 60,
            Collectors.mapping(Student::name, Collectors.toList())
        )
    );
System.out.println("Passed: " + namesByPass.get(true));
System.out.println("Failed: " + namesByPass.get(false));

countingin ja summarizingIntin yhdistäminen

Collectors.summarizingInt() laskee yhdellä läpikäynnillä määrän, summan, pienimmän ja suurimman arvon sekä keskiarvon:

IntSummaryStatistics stats =
    students.stream().collect(
        Collectors.summarizingInt(Student::score)
    );
System.out.println("Count: " + stats.getCount());
System.out.println("Average: " + stats.getAverage());
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());

Todellinen käyttötapaus: A/B-testin jako

Jakakaa käyttäjät kontrolli- ja käsittelyryhmiin A/B-testiä varten:

record User(String id, boolean isInTreatment) {}
List<User> users = List.of(
    new User("u1",true), new User("u2",false),
    new User("u3",true), new User("u4",false)
);

Map<Boolean, Long> split =
    users.stream().collect(
        Collectors.partitioningBy(User::isInTreatment, Collectors.counting())
    );
System.out.println("Treatment: " + split.get(true)); // 2
System.out.println("Control: " + split.get(false));  // 2

Frekvenssikartta groupingBy + counting -yhdistelmällä

Laskekaa kunkin alkion esiintymät eli muodostakaa sanojen frekvenssikartta:

List<String> words2 = List.of("apple","banana","apple","cherry","banana","apple");

Map<String, Long> freq =
    words2.stream().collect(
        Collectors.groupingBy(w -> w, Collectors.counting())
    );
freq.entrySet().stream()
    .sorted(Map.Entry.<String,Long>comparingByValue().reversed())
    .forEach(e -> System.out.println(e.getKey()+": "+e.getValue()));

partitioningBy palauttaa aina molemmat avaimet

Toisin kuin groupingBy, partitioningBy palauttaa aina map-rakenteen, jossa ovat sekä true- että false-avaimet, vaikka toinen ryhmistä olisi tyhjä. Näin vältetään NullPointerException map.get(true)-kutsussa.

List<Integer> allEven = List.of(2,4,6);
Map<Boolean, List<Integer>> m =
    allEven.stream().collect(Collectors.partitioningBy(n -> n % 2 != 0));
System.out.println(m.get(true));  // [] (empty, not null)
System.out.println(m.get(false)); // [2, 4, 6]

Suorituskyky: yksi läpikäynti

Sekä partitioningBy että counting toimivat yhdellä streamin läpikäynnillä — O(n). Ne eivät edellytä järjestämistä. Siksi ne ovat huomattavasti tehokkaampia kuin filter-metodin kutsuminen kahdesti tai tietojen järjestäminen ennen ryhmittelyä.

Pikatarkistus

Mikä on Collectors.partitioningBy(predicate)-metodin palautustyyppi?

Kertaus: partitioningBy ja counting

Keskeiset opit:

  • partitioningBy jakaa alkiot täsmälleen kahteen ryhmään (true/false)
  • Molemmat avaimet ovat aina mukana, joten NPE-riskiä ei ole toisin kuin groupingBy-operaatiossa
  • counting() laskee alkiot, ja sitä voi käyttää ryhmien downstream-kerääjänä
  • summarizingInt/Long/Double tuottaa määrän, summan, minimiarvon, maksimiarvon ja keskiarvon yhdellä läpikäynnillä
  • Kaikki toimivat yhdellä O(n)-suorituskyvyn stream-läpikäynnillä
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”partitioningBy ja counting” ilmainen?

Kyllä – oppitunnin ”partitioningBy ja counting” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”partitioningBy ja counting”?

Jaa stream kahdeksi ryhmäksi partitioningBy-metodilla ja laske alkiot counting-metodilla. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”partitioningBy ja counting”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. groupingBy: alkioiden luokittelu
  2. partitioningBy ja counting
  3. toMap, joining ja summarizing
  4. Mukautetun kerääjän rakentaminen
← Takaisin: Java Academy