Splits een lijst in delen in Kotlin

1. Inleiding

Laten we zeggen dat we een array hebben zoals [a, b, c, d, e, f] en we willen de elementen opsplitsen in aparte groepen, zoals [[a, b], [c, d], [e, f]] of [[a, b, c], [d], [e, f]].

In deze tutorial zullen we dit bereiken door enkele verschillen tussen Kotlin's te onderzoeken groupBy, chunked, en met vensters.

2. Een lijst opsplitsen in een lijst met paren

Voor onze voorbeelden gebruiken we twee lijsten: een met een even aantal elementen en een met een oneven aantal elementen:

val evenList = listOf (0, "a", 1, "b", 2, "c"); val unevenList = listOf (0, "a", 1, "b", 2, "c", 3);

Het is duidelijk dat we onze kunnen verdelen evenList in precies drie paren. Echter, onze onevenList zal een extra element hebben.

In de rest van deze sectie zullen we verschillende implementaties zien voor het splitsen van onze twee lijsten, inclusief hoe ze omgaan met het extra element in onevenList.

2.1. Gebruik makend van groupBy

Laten we eerst een oplossing implementeren met groupBy. We maken een lijst met oplopende nummers en gebruiken groupBy om ze te splitsen:

val numberList = listOf (1, 2, 3, 4, 5, 6); numberList.groupBy {(it + 1) / 2} .waarden

Dit geeft het gewenste resultaat:

[[1, 2], [3, 4], [5, 6]]

Hoe werkt het? Goed, groupBy voert de geleverde functie uit (het + 1) / 2 op elk element:

  • (1 + 1) / 2 = 1
  • (2 + 1) / 2 = 1,5, afgerond op 1
  • (3 + 1) / 2 = 2
  • (4 + 1) / 2 = 2,5, afgerond op 2
  • (5 + 1) / 2 = 3
  • (6 + 1) / 2 = 3,5, afgerond op 3

Dan, groupBy groepeert de elementen in de lijst die hetzelfde resultaat opleverden.

Als we nu hetzelfde doen met een ongelijke lijst:

val numberList = listOf (1, 2, 3, 4, 5, 6, 7); numberList.groupBy {(it + 1) / 2} .waarden

We krijgen alle paren en een extra element:

[[1, 2], [3, 4], [5, 6], [7]]

Maar, als we wat verder gaan met enkele willekeurige getallen:

val numberList = listOf (1, 3, 8, 20, 23, 30); numberList.groupBy {(it + 1) / 2} .waarden

We krijgen iets dat volkomen ongewenst is:

[[1], [3], [8], [20], [23], [30]]

De reden is simpel; toepassen van de (het + 1) / 2 functie op elk element geeft: 1, 2, 4, 10, 12, 15. Alle resultaten verschillen, dus er zijn geen elementen bij elkaar gegroepeerd.

Wanneer we onze evenList of onevenList, het is nog erger - de code compileert niet, aangezien de functie niet kan worden toegepast Snaren.

2.2. Gebruik makend van groupBy en withIndex

Echt, als we een willekeurige lijst in paren willen groeperen, we willen de waarde door onze functie, maar de inhoudsopgave:

evenList.withIndex () .groupBy {it.index / 2} .map {it.value.map {it.value}}

Dit retourneert de lijst met paren die we willen:

[[0, "a"], [1, "b"], [2, "c"]]

Bovendien, als we de onevenList, we krijgen zelfs ons aparte element:

[[0, "a"], [1, "b"], [2, "c"], [3]]

2.3. Gebruik makend van groupBy Met foldIndexed

We kunnen een stap verder gaan dan alleen gebruiken inhoudsopgave en programmeer een beetje meer met foldIndexed om enkele toewijzingen op te slaan:

evenList.foldIndexed (ArrayList(evenList.size / 2)) {index, acc, item -> if (index% 2 == 0) {acc.add (ArrayList (2))} acc.last (). add (item) acc}

Hoewel een beetje meer uitgebreid, de foldIndexed oplossing voert eenvoudig de bewerking uit op elk element, terwijl de withIndex functie maakt eerst een iterator en omhult elk element.

2.4. Gebruik makend van in stukken gesneden

Maar we kunnen dit eleganter doen met in stukken gesneden. Dus laten we de methode toepassen op onze evenList:

evenList.chunked (2)

De evenList geeft ons de paren die we willen:

[[0, "a"], [1, "b"], [2, "c"]]

Terwijl de onevenList geeft ons de paren en het extra element:

[[0, "a"], [1, "b"], [2, "c"], [3]]

2.5. Gebruik makend van met vensters

En in stukken gesneden werkt echt goed, maar soms hebben we wat meer controle nodig.

Het kan bijvoorbeeld zijn dat we moeten specificeren of we alleen paren willen, of dat we het extra element willen opnemen. De met vensters methode geeft ons een gedeeltelijke Windows Boolean, wat aangeeft of we het gedeeltelijke resultaat willen of niet.

Standaard, gedeeltelijke Windows is false. De volgende uitspraken leveren dus hetzelfde resultaat op:

evenList.windowed (2, 2) unevenList.windowed (2, 2, false)

Beiden retourneren de lijst zonder het afzonderlijke element:

[[0, "a"], [1, "b"], [2, "c"]]

Eindelijk, als we gaan zitten gedeeltelijke Windows naar waar om het gedeeltelijke resultaat op te nemen:

unevenList.windowed (2, 2, true)

We krijgen de lijst met paren plus het afzonderlijke element:

[[0, "a"], [1, "b"], [2, "c"], [3]]

3. Conclusie

Gebruik makend van groupBy is een leuke programmeeroefening, maar het kan behoorlijk foutgevoelig zijn. Sommige fouten kunnen eenvoudig worden opgelost door een inhoudsopgave.

Om de code te optimaliseren, kunnen we zelfs foldIndexed. Dit resulteert echter in nog meer code. Gelukkig is de in stukken gesneden method biedt ons dezelfde functionaliteit out-of-the-box.

Bovendien is de met vensters methode biedt aanvullende configuratie-opties. Gebruik indien mogelijk het in stukken gesneden methode, en als we aanvullende configuratie nodig hebben, moeten we de met vensters methode.

Zoals gewoonlijk is de volledige broncode beschikbaar op GitHub.