Matrixbewerkingen in Java

1. Overzicht

Elke Java-ontwikkelaar weet dat het produceren van een schone, efficiënte oplossing bij het werken met array-bewerkingen niet altijd gemakkelijk te realiseren is. Toch zijn ze een centraal onderdeel van het Java-ecosysteem - en we zullen er bij verschillende gelegenheden mee te maken krijgen.

Om deze reden is het goed om een ​​'spiekbriefje' te hebben - een samenvatting van de meest gebruikelijke procedures om ons te helpen de puzzel snel op te lossen. Deze tutorial is handig in die situaties.

2. Arrays en helperklassen

Voordat u verder gaat, is het handig om te begrijpen wat een array in Java is en hoe u deze kunt gebruiken. Als het de eerste keer is dat je ermee werkt in Java, raden we je aan om naar dit vorige bericht te kijken, waar we alle basisconcepten hebben behandeld.

Houd er rekening mee dat de basisbewerkingen die een array ondersteunt, op een bepaalde manier beperkt zijn. Het is niet ongebruikelijk om complexe algoritmen te zien om relatief eenvoudige taken uit te voeren als het gaat om arrays.

Om deze reden zullen we voor de meeste van onze bewerkingen hulpklassen en -methoden gebruiken om ons te helpen: het Arrays klasse geleverd door Java en de Apache's ArrayUtils een.

Om de laatste in ons project op te nemen, moeten we de Apache Commons-afhankelijkheid toevoegen:

 org.apache.commons commons-lang3 3.8.1 

We kunnen de nieuwste versie van dit artefact bekijken op Maven Central.

3. Verkrijg het eerste en laatste element van een array

Dit is een van de meest voorkomende en eenvoudige taken dankzij de toegang per index van arrays.

Laten we beginnen met het declareren en initialiseren van een int array die in al onze voorbeelden zal worden gebruikt (tenzij we anders specificeren):

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

Wetende dat het eerste item van een array is gekoppeld aan de indexwaarde 0 en dat het een lengte attribuut dat we kunnen gebruiken, dan is het eenvoudig om erachter te komen hoe we deze twee elementen kunnen krijgen:

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

4. Haal een willekeurige waarde uit een array

Door de java.util.Random object kunnen we gemakkelijk elke waarde uit onze array halen:

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

5. Voeg een nieuw item toe aan een array

Zoals we weten, bevatten arrays een vaste grootte van waarden. Daarom kunnen we niet zomaar een item toevoegen en deze limiet overschrijden.

We moeten beginnen met het declareren van een nieuwe, grotere array en de elementen van de basisarray naar de tweede kopiëren.

Gelukkig is de Arrays class biedt een handige methode om de waarden van een array te repliceren naar een nieuwe structuur met verschillende afmetingen:

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

Optioneel, als het ArrayUtils klasse is toegankelijk in ons project, we kunnen er gebruik van maken voeg methode toe (of zijn Voeg alles toe alternatief) om ons doel te bereiken in een eenregelige verklaring:

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

Zoals we ons kunnen voorstellen, wijzigt deze methode het origineel niet array voorwerp; we moeten zijn output toewijzen aan een nieuwe variabele.

6. Voeg een waarde in tussen twee waarden

Vanwege het teken met geïndexeerde waarden is het invoegen van een item in een array tussen twee andere items geen triviale taak.

Apache beschouwde dit als een typisch scenario en implementeerde een methode in zijn ArrayUtils class om de oplossing te vereenvoudigen:

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

We moeten de index specificeren waarin we de waarde willen invoegen, en de uitvoer zal een nieuwe array zijn met een groter aantal elementen.

Het laatste argument is een variabel argument (a.k.a. vararg) dus kunnen we een willekeurig aantal items in de array invoegen.

7. Vergelijk twee arrays

Ook al zijn arrays Voorwerps en geef daarom een is gelijk aan methode gebruiken ze de standaardimplementatie ervan en vertrouwen ze alleen op referentiegelijkheid.

We kunnen hoe dan ook een beroep doen op de java.util.Arraysis gelijk aan methode om te controleren of twee array-objecten dezelfde waarden bevatten:

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

Opmerking: deze methode is niet effectief voor gekartelde arrays. De juiste methode om de gelijkheid van multidimensionale structuren te verifiëren, is de Arrays.deepEquals een.

8. Controleer of een array leeg is

Dit is een ongecompliceerde opdracht, aangezien we de lengte attribuut van arrays:

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

Bovendien hebben we ook een nulveilige methode in het ArrayUtils helper class die we kunnen gebruiken:

boolean isEmpty = ArrayUtils.isEmpty (matrix);

Deze functie hangt nog steeds af van de lengte van de datastructuur, die nulls en lege subarrays ook als geldige waarden beschouwt, dus we zullen deze randgevallen in de gaten moeten houden:

// Dit zijn lege arrays Geheel getal [] array1 = {}; Geheel getal [] array2 = null; Geheel getal [] array3 = nieuw geheel getal [0]; // Al deze zullen NIET als leeg geheel getal worden beschouwd [] array3 = {null, null, null}; Geheel getal [] [] array4 = {{}, {}, {}}; Geheel getal [] array5 = nieuw geheel getal [3];

9. Hoe de elementen van een array door elkaar worden geschud

Om de items in een array door elkaar te halen, kunnen we de ArrayUtil‘S functie:

ArrayUtils.shuffle (matrix);

Dit is een leegte methode en werkt op de werkelijke waarden van de array.

10. Box en Unbox Arrays

We komen vaak methoden tegen die alleen ondersteunen Voorwerp-gebaseerde arrays.

Nogmaals de ArrayUtils helper class is handig om een ​​boxed versie van onze primitieve array te krijgen:

Geheel getal [] lijst = ArrayUtils.toObject (array);

De omgekeerde werking is ook mogelijk:

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

11. Verwijder duplicaten uit een array

De eenvoudigste manier om duplicaten te verwijderen, is door de array naar een Set implementatie.

Zoals we wellicht weten, Verzamelings gebruiken Generics en ondersteunen daarom geen primitieve types.

Om deze reden, als we geen objectgebaseerde arrays behandelen zoals in ons voorbeeld, moeten we eerst onze waarden in een box plaatsen:

// Box Integer [] list = ArrayUtils.toObject (array); // Verwijder duplicaten Set set = new HashSet (Arrays.asList (lijst)); // Create array en unbox return ArrayUtils.toPrimitive (set.toArray (new Integer [set.size ()]));

Opmerking: we kunnen andere technieken gebruiken om te converteren tussen een array en een Set object ook.

Als we de volgorde van onze elementen willen behouden, moeten we ook een andere gebruiken Set implementatie, zoals een LinkedHashSet.

12. Hoe u een array kunt afdrukken

Hetzelfde als bij de is gelijk aan methode, de array's toString functie gebruikt de standaardimplementatie die wordt geboden door de Voorwerp class, wat niet erg handig is.

Beide Arrays en ArrayUtils klassen worden geleverd met hun implementaties om de datastructuren om te zetten in een leesbaar Draad.

Afgezien van het iets andere formaat dat ze gebruiken, is het belangrijkste onderscheid hoe ze multidimensionale objecten behandelen.

De klasse van Java Util biedt twee statische methoden die we kunnen gebruiken:

  • toString: werkt niet goed met gekartelde arrays
  • deepToString: ondersteunt alle Voorwerp-gebaseerde arrays, maar compileert niet met primitieve array-argumenten

Aan de andere kant, Apache's implementatie biedt een enkele toString methode die in ieder geval correct werkt:

String arrayAsString = ArrayUtils.toString (array);

13. Wijs een array toe aan een ander type

Het is vaak handig om bewerkingen toe te passen op alle array-items, en deze mogelijk naar een ander type object te converteren.

Met dit doel voor ogen, we zullen proberen een flexibele hulpmethode te maken met behulp van Generics:

openbare statische U [] mapObjectArray (T [] array, functie functie, klasse targetClazz) {U [] newArray = (U []) Array.newInstance (targetClazz, array.length); voor (int i = 0; i <array.length; i ++) {newArray [i] = function.apply (array [i]); } return newArray; }

Als we Java 8 niet gebruiken in ons project, kunnen we het Functie argument, en maak een methode voor elke mapping die we moeten uitvoeren.

We kunnen onze generieke methode nu hergebruiken voor verschillende bewerkingen. Laten we twee testcases maken om dit te illustreren:

@Test public void whenMapArrayMultiplyingValues_thenReturnMultipliedArray () {Geheel getal [] multipliedExpectedArray = nieuw geheel getal [] {6, 10, 4, 10, 28, 8}; Geheel getal [] output = MyHelperClass.mapObjectArray (array, waarde -> waarde * 2, Integer.class); assertThat (output) .containsExactly (multipliedExpectedArray); } @Test public void whenMapDividingObjectArray_thenReturnMultipliedArray () {Double [] multipliedExpectedArray = new Double [] {1.5, 2.5, 1.0, 2.5, 7.0, 2.0}; Double [] output = MyHelperClass.mapObjectArray (array, waarde -> waarde / 2.0, Double.class); assertThat (output) .containsExactly (multipliedExpectedArray); }

Voor primitieve typen moeten we eerst onze waarden omkaderen.

Als alternatief kunnen we ons wenden tot Java 8's Streams om de mapping voor ons uit te voeren.

We zullen de array moeten transformeren in een Stroom van Voorwerps eerste. We kunnen dit doen met de Arrays.stream methode.

Als we bijvoorbeeld onze int waarden naar een gewoonte Draad vertegenwoordiging, zullen we dit implementeren:

String [] stringArray = Arrays.stream (array) .mapToObj (waarde -> String.format ("Waarde:% s", waarde)) .toArray (String [] :: nieuw);

14. Filter waarden in een array

Het filteren van waarden uit een verzameling is een veel voorkomende taak die we mogelijk meer dan één keer moeten uitvoeren.

Dit komt omdat op het moment dat we de array maken die de waarden zal ontvangen, we niet zeker kunnen zijn van de uiteindelijke grootte. Daarom we vertrouwen op de Strooms naderen opnieuw.

Stel je voor dat we alle oneven getallen uit een array willen verwijderen:

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

15. Andere veel voorkomende array-bewerkingen

Er zijn natuurlijk tal van andere array-bewerkingen die we mogelijk moeten uitvoeren.

Afgezien van degene die in deze zelfstudie worden getoond, hebben we uitgebreid andere bewerkingen behandeld in de speciale berichten:

  • Controleer of een Java-array een waarde bevat
  • Hoe een array in Java te kopiëren
  • Het eerste element van een array verwijderen
  • De min en max vinden in een array met Java
  • Zoek som en gemiddelde in een Java-array
  • Hoe een array in Java te omkeren
  • Arrays en verzamelingen samenvoegen en splitsen in Java
  • Combineren van verschillende soorten verzamelingen in Java
  • Zoek alle getallenparen in een array die bij elkaar optellen tot een bepaald bedrag
  • Sorteren in Java
  • Efficiënte woordfrequentiecalculator in Java
  • Invoegsortering in Java

16. Conclusie

Arrays zijn een van de kernfunctionaliteiten van Java, en daarom is het erg belangrijk om te begrijpen hoe ze werken en om te weten wat we er wel en niet mee kunnen doen.

In deze zelfstudie hebben we geleerd hoe we arraybewerkingen op de juiste manier kunnen afhandelen in veelvoorkomende scenario's.

Zoals altijd is de volledige broncode van de werkende voorbeelden beschikbaar op onze Github-repo.