Array-operasjoner i Java

1. Oversikt

Enhver Java-utvikler vet at det ikke alltid er enkelt å produsere en ren, effektiv løsning når man arbeider med array-operasjoner. Likevel er de en sentral del av Java-økosystemet - og vi må håndtere dem ved flere anledninger.

Av denne grunn er det bra å ha et 'cheat sheet' - et sammendrag av de vanligste prosedyrene som hjelper oss med å takle puslespillet raskt. Denne opplæringen vil være nyttig i de situasjonene.

2. Arrays og hjelperklasser

Før du fortsetter, er det nyttig å forstå hva som er en matrise i Java, og hvordan du bruker den. Hvis det er første gang du jobber med det i Java, foreslår vi at du ser på dette forrige innlegget der vi dekket alle grunnleggende konsepter.

Vær oppmerksom på at de grunnleggende operasjonene som en matrise støtter er på en bestemt måte begrenset. Det er ikke uvanlig å se komplekse algoritmer for å utføre relativt enkle oppgaver når det gjelder matriser.

Av den grunn bruker vi hjelperklasser og metoder for å hjelpe oss: de fleste av våre operasjoner Arrays klasse levert av Java og Apache's ArrayUtils en.

For å inkludere sistnevnte i prosjektet vårt, må vi legge til Apache Commons avhengighet:

 org.apache.commons commons-lang3 3.8.1 

Vi kan sjekke ut den nyeste versjonen av denne gjenstanden på Maven Central.

3. Få det første og siste elementet i en matrise

Dette er en av de vanligste og mest enkle oppgavene takket være tilgangen etter indeksen til matriser.

La oss starte med å erklære og initialisere en int array som skal brukes i alle eksemplene våre (med mindre vi spesifiserer noe annet):

int [] array = new int [] {3, 5, 2, 5, 14, 4};

Å vite at det første elementet i en matrise er assosiert med indeksverdien 0 og at den har en lengde attributt som vi kan bruke, så er det enkelt å finne ut hvordan vi kan få disse to elementene:

int firstItem = array [0]; int lastItem = array [array.length - 1];

4. Få en tilfeldig verdi fra en matrise

Ved å bruke java.util.Random objekt kan vi enkelt få hvilken som helst verdi fra vårt utvalg:

int anyValue = array [new Random (). nextInt (array.length)];

5. Legg til et nytt element i en serie

Som vi vet har matriser en fast størrelse på verdiene. Derfor kan vi ikke bare legge til en vare og overskride denne grensen.

Vi må begynne med å erklære en ny, større matrise og kopiere elementene i basisenheten til den andre.

Heldigvis, den Arrays klasse gir en praktisk metode for å replikere verdiene til en matrise til en ny struktur i annen størrelse:

int [] newArray = Arrays.copyOf (array, array.length + 1); newArray [newArray.length - 1] = newItem;

Eventuelt hvis ArrayUtils klasse er tilgjengelig i prosjektet vårt, kan vi bruke det legg til metode (eller dens Legg til alle alternativ) for å oppnå vårt mål i en uttalelse på en linje:

int [] newArray = ArrayUtils.add (array, newItem);

Som vi kan forestille oss, endrer ikke denne metoden originalen array gjenstand; vi må tilordne utgangen til en ny variabel.

6. Sett inn en verdi mellom to verdier

På grunn av karakteren med indekserte verdier er det ikke en triviell jobb å sette inn et element i en matrise mellom to andre.

Apache betraktet dette som et typisk scenario og implementerte en metode i sitt ArrayUtils klasse for å forenkle løsningen:

int [] largerArray = ArrayUtils.insert (2, array, 77);

Vi må spesifisere indeksen der vi ønsker å sette inn verdien, og utgangen vil være en ny matrise som inneholder et større antall elementer.

Det siste argumentet er et variabelt argument (a.k.a. vararg) slik at vi kan sette inn et hvilket som helst antall elementer i matrisen.

7. Sammenlign to matriser

Selv om arrays er det Gjenstands og derfor gi en er lik metoden, bruker de standardimplementeringen av den, og stoler bare på referanselikhet.

Vi kan uansett påberope oss java.util.Arrayerer lik metode for å sjekke om to matriseobjekter inneholder de samme verdiene:

boolske areEqual = Arrays.equals (array1, array2);

Merk: denne metoden er ikke effektiv for takkede matriser. Den riktige metoden for å verifisere flerdimensjonale strukturers likhet er Arrays.deepEquals en.

8. Sjekk om en matrise er tom

Dette er en ukomplisert oppgave med tanke på at vi kan bruke lengde attributt for matriser:

boolsk isEmpty = array == null || array.length == 0;

Videre har vi også en null-sikker metode i ArrayUtils hjelperklasse som vi kan bruke:

boolsk isEmpty = ArrayUtils.isEmpty (array);

Denne funksjonen avhenger fortsatt av lengden på datastrukturen, som også anser null og tomme underarrayer som gyldige verdier, så vi må holde øye med disse kantsakene:

// Dette er tomme matriser Heltall [] array1 = {}; Heltall [] array2 = null; Heltall [] array3 = nytt Heltall [0]; // Alle disse blir IKKE ansett som tomme Heltall [] array3 = {null, null, null}; Heltall [] [] array4 = {{}, {}, {}}; Heltall [] array5 = nytt Heltall [3];

9. Hvordan blande elementene i en matrise

For å blande elementene i en matrise kan vi bruke ArrayUtilSin funksjon:

ArrayUtils.shuffle (array);

Dette er en tomrom metode og opererer på de faktiske verdiene til matrisen.

10. Box og Unbox Arrays

Vi kommer ofte over metoder som bare støtter Gjenstand-baserte matriser.

Igjen den ArrayUtils hjelperklasse er nyttig for å få en boksversjon av vårt primitive utvalg:

Heltall [] liste = ArrayUtils.toObject (matrise);

Den omvendte operasjonen er også mulig:

Heltall [] objectArray = {3, 5, 2, 5, 14, 4}; int [] array = ArrayUtils.toPrimitive (objectArray);

11. Fjern duplikater fra en serie

Den enkleste måten å fjerne duplikater på er å konvertere matrisen til en Sett gjennomføring.

Som vi kanskje vet, Samlings bruker generiske stoffer og støtter derfor ikke primitive typer.

Av denne grunn, hvis vi ikke håndterer objektbaserte matriser som i eksemplet vårt, må vi først legge inn verdiene våre:

// Box Integer [] list = ArrayUtils.toObject (array); // Fjern duplikater Set set = new HashSet (Arrays.asList (list)); // Opprette matrise og avkoble retur ArrayUtils.toPrimitive (set.toArray (nytt heltal [set.size ()]));

Merk: vi kan bruke andre teknikker for å konvertere mellom en matrise og en Sett objekt også.

Også, hvis vi trenger å bevare rekkefølgen på elementene våre, må vi bruke en annen Sett implementering, for eksempel en LinkedHashSet.

12. Hvordan skrive ut en serie

Samme som med er lik metoden, matrisen toString funksjonen bruker standardimplementeringen som tilbys av Gjenstand klasse, noe som ikke er veldig nyttig.

Både Arrays og ArrayUtils klasser sendes med sine implementeringer for å konvertere datastrukturene til en lesbar String.

Bortsett fra det litt forskjellige formatet de bruker, er det viktigste skillet hvordan de behandler flerdimensjonale objekter.

Java Util-klassen gir to statiske metoder vi kan bruke:

  • toString: fungerer ikke bra med takkede matriser
  • deepToString: støtter noe Gjenstand-baserte matriser, men kompilerer ikke med primitive arrayargumenter

På den andre siden, Apache implementering tilbyr en enkelt toString metode som fungerer riktig i alle fall:

String arrayAsString = ArrayUtils.toString (array);

13. Kartlegg en serie til en annen type

Det er ofte nyttig å bruke operasjoner på alle matriseelementer, eventuelt konvertere dem til en annen type objekt.

Med dette målet i tankene, Vi prøver å lage en fleksibel hjelpemetode ved hjelp av Generics:

public static U [] mapObjectArray (T [] array, Function function, Class targetClazz) {U [] newArray = (U []) Array.newInstance (targetClazz, array.length); for (int i = 0; i <array.length; i ++) {newArray [i] = function.apply (array [i]); } returner newArray; }

Hvis vi ikke bruker Java 8 i prosjektet vårt, kan vi forkaste Funksjon argument, og lag en metode for hver kartlegging som vi trenger å utføre.

Vi kan nå gjenbruke vår generiske metode for forskjellige operasjoner. La oss lage to testtilfeller for å illustrere dette:

@Test offentlig ugyldig når MapArrayMultiplyingValues_thenReturnMultipliedArray () {Integer [] multipliedExpectedArray = new Integer [] {6, 10, 4, 10, 28, 8}; Heltall [] utgang = MyHelperClass.mapObjectArray (matrise, verdi -> verdi * 2, Heltall.klasse); assertThat (output) .containsExactly (multiplisedExpectedArray); } @Test offentlig ugyldig når MapDividingObjectArray_thenReturnMultipliedArray () {Double [] multiplierExpectedArray = new Double [] {1.5, 2.5, 1.0, 2.5, 7.0, 2.0}; Dobbelt [] output = MyHelperClass.mapObjectArray (array, verdi -> verdi / 2.0, Double.class); assertThat (output) .containsExactly (multiplisedExpectedArray); }

For primitive typer må vi først sette inn verdiene våre.

Som et alternativ kan vi vende oss til Java 8s Streams for å utføre kartleggingen for oss.

Vi må transformere matrisen til en Strøm av Gjenstands først. Vi kan gjøre det med Arrays.stream metode.

For eksempel hvis vi vil kartlegge våre int verdier til en skikk String representasjon, vil vi implementere dette:

Streng [] stringArray = Arrays.stream (array) .mapToObj (verdi -> String.format ("Verdi:% s", verdi)) .toArray (Streng [] :: ny);

14. Filtrer verdier i en matrise

Å filtrere ut verdier fra en samling er en vanlig oppgave som vi kanskje må utføre i mer enn en anledning.

Dette er fordi vi ikke kan være sikre på den endelige størrelsen når vi lager matrisen som vil motta verdiene. Derfor, vi vil stole på Strøms tilnærming igjen.

Tenk deg at vi vil fjerne alle oddetall fra en matrise:

int [] evenArray = Arrays.stream (array) .filter (verdi -> verdi% 2 == 0) .toArray ();

15. Andre vanlige matriser

Det er selvfølgelig mange andre array-operasjoner som vi kanskje trenger å utføre.

Bortsett fra de som er vist i denne opplæringen, har vi omfattende dekket andre operasjoner i de dedikerte innleggene:

  • Sjekk om en Java Array inneholder en verdi
  • Hvordan kopiere en matrise i Java
  • Fjerne det første elementet i en serie
  • Finne min og maks i en matrise med Java
  • Finn sum og gjennomsnitt i en Java Array
  • Hvordan invertere en matrise i Java
  • Bli med og del arrays og samlinger i Java
  • Kombinere forskjellige typer samlinger i Java
  • Finn alle tallene i en serie som utgjør en gitt sum
  • Sortering i Java
  • Effektiv Word Frequency Calculator i Java
  • Innsetting Sorter i Java

16. Konklusjon

Arrays er en av kjernefunksjonalitetene til Java, og derfor er det veldig viktig å forstå hvordan de fungerer og å vite hva vi kan og ikke kan gjøre med dem.

I denne opplæringen lærte vi hvordan vi kan håndtere arrayoperasjoner riktig i vanlige scenarier.

Som alltid er den fullstendige kildekoden til arbeidseksemplene tilgjengelig på Github-repoen vår.