Filtrovanie zbierky Java podľa zoznamu

1. Prehľad

Filtrovanie a Zbierka od a Zoznam je bežný scenár obchodnej logiky. Existuje veľa spôsobov, ako to dosiahnuť. Niektoré však môžu viesť k nedostatočnému riešeniu, ak nebudú vykonané správne.

V tomto návode porovnáme niektoré implementácie filtrovania a prediskutujeme ich výhody a nevýhody.

2. Pomocou a Pre každý Slučka

Začneme najklasickejšou syntaxou, slučkou pre každú.

Pre tento a všetky ďalšie príklady v tomto článku použijeme nasledujúcu triedu:

public class Employee {private Integer employeeNumber; súkromné ​​meno reťazca; private Integer departmentId; // Štandardný konštruktor, getre a setre. }

Pre všetky príklady použijeme pre jednoduchosť nasledujúce metódy:

private List buildEmployeeList () {return Arrays.asList (new Employee (1, "Mike", 1), new Employee (2, "John", 1), new Employee (3, "Mary", 1), new Employee ( 4, „Joe“, 2), nový zamestnanec (5, „Nicole“, 2), nový zamestnanec (6, „Alice“, 2), nový zamestnanec (7, „Bob“, 3), nový zamestnanec (8, „Scarlett“, 3)); } private List employeeNameFilter () {return Arrays.asList ("Alice", "Mike", "Bob"); }

Pre náš príklad vyfiltrujeme prvý zoznam Zamestnanci na základe druhého zoznamu s Zamestnanec mená nájsť iba Zamestnanci s tými konkrétnymi menami.

Teraz sa pozrime na tradičný prístup - opakovanie oboch zoznamov hľadaním zhôd:

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingForEachLoop () {Listfiltrovaný zoznam = nový ArrayList (); Zoznam originalList = buildEmployeeList (); Názov zoznamuFilter = employeeNameFilter (); pre (Zamestnanec zamestnanec: originalList) {pre (Názov reťazca: nameFilter) {if (employee.getName (). equals (name)) {filtrList.add (zamestnanec); // prestávka; }}} assertThat (filtrovanýList.size (), je (nameFilter.size ())); }

Toto je jednoduchá syntax, ale je dosť podrobná a v skutočnosti dosť neefektívna. Jednoducho povedané iteruje cez karteziánsky súčin týchto dvoch množín aby sme dostali našu odpoveď.

Dokonca aj pridanie a prestávka predčasný odchod bude v priemernom prípade stále iterovať v rovnakom poradí ako karteziánsky súčin.

Ak nazveme veľkosť zoznamu zamestnancov n, potom menoFilter bude na objednávku rovnako veľká, čo nám dá an O (n2) klasifikácia.

3. Používanie streamov a Zoznam obsahuje

Teraz zreferujeme predchádzajúcu metódu pomocou lambdas na zjednodušenie syntaxe a zlepšenie čitateľnosti. Použime tiež Zoznam obsahuje metóda ako lambda filter:

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambda () {Zoznam filtrovaný zoznam; Zoznam originalList = buildEmployeeList (); Názov zoznamuFilter = employeeNameFilter (); filterList = originalList.stream () .filter (zamestnanec -> nameFilter.contains (employee.getName ())) .collect (Collectors.toList ()); assertThat (filterList.size (), je (nameFilter.size ())); }

Použitím Stream API, čitateľnosť sa výrazne zlepšila, ale náš kód zostáva rovnako neefektívny ako naša predchádzajúca metóda, pretože je stále interne iteruje prostredníctvom karteziánskeho súčinu. Máme teda rovnaké O (n2) klasifikácia.

4. Používanie streamov s HashSet

Na zlepšenie výkonu musíme použiť HashSet # obsahuje metóda. Táto metóda sa líši od Zoznam obsahuje pretože vykonáva a hash kód vyhľadávanie, čo nám dáva konštantný počet operácií:

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambdaAndHashSet () {Listfiltrovaný zoznam; Zoznam originalList = buildEmployeeList (); Nastaviť nameFilterSet = employeeNameFilter (). Stream (). Collect (Collectors.toSet ()); filtrovanýZoznam = originalList.stream () .filter (zamestnanec -> nameFilterSet.contains (employee.getName ())) .collect (Collectors.toList ()); assertThat (filterList.size (), je (nameFilterSet.size ())); }

Používaním HashSet, účinnosť nášho kódu sa výrazne zlepšila, pričom to neovplyvnilo čitateľnosť. Odkedy HashSet # obsahuje beží v konštantnom čase, vylepšili sme našu klasifikáciu na O (n).

5. Záver

V tomto rýchlom výučbe sme sa naučili, ako filtrovať a Zbierka od a Zoznam hodnôt a nevýhod použitia toho, čo sa môže javiť ako najpriamejšia metóda.

Musíme vždy brať do úvahy efektívnosť, pretože náš kód by mohol skončiť v obrovských množinách údajov a problémy s výkonom by mohli mať v takýchto prostrediach katastrofické následky.

Celý kód uvedený v tomto článku je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found