Sådan reverseres arrays i JavaScript uden at bruge .reverse ()

På stedet og ude af sted

Foto af Guillaume Bolduc på Unsplash

En typisk JavaScript-udfordring eller interviewspørgsmål har at gøre med at vende arrays på stedet og out-of-place. Tag specifikt dette problem fra Eloquent JavaScript, 2. udgave:

Skriv to funktioner reverseArray og reverseArrayInPlace. Den første, reverseArray, tager en matrix som et argument og producerer en ny matrix, der har de samme elementer i den omvendte rækkefølge. Den anden, reverseArrayInPlace, gør, hvad den omvendte metode gør: den ændrer den matrix, der er givet som argument for at vende dets elementer. Ingen af ​​dem må bruge standard reverse-metoden.

Det er kickeren: du kan ikke bruge metoden .reverse ().

Jeg arbejdede igennem dette problem i fortiden, men nu, hvor jeg kommer tilbage til at studere JavaScript efter en pause, tog det mig et stykke tid at ombryde hovedet igen. Især vende arrayet på plads. For at hjælpe mig med bedre at forstå og tænke igennem dette problem besluttede jeg at skrive denne artikel.

At vende et array ud af sted

For at starte skal vi lave to arrays:

var array1 = ["ja", "nej", "måske", "altid", "undertiden", "aldrig", "hvis"];
var array2 = [5,8,2,9,5,6,3,1];

For funktionen reverseArray, hvis vi vil producere en ny matrix, har vi brug for en tom matrix for at udfylde senere:

var newArray = [];

Skrivning af trinnene ud i pseudokode:

// 1) Jeg vil tage det sidste element i matrixen og derefter tilføje det til den nye array.
// 2) For at gøre dette skal jeg gå igennem matrixen fra slutningen til begyndelsen, fordi jeg vil have, at det sidste element skal være først.
// 3) Jeg vil sende indholdet af 'newArray', når for-loop er færdig.

Lad os først komme med vores for loop. For at starte i slutningen af ​​matrixen ønsker vi at indstille i lig med længden af ​​arrayen minus 1, da indekset for en matrix altid starter ved nul.

var i = array.length - 1

For eksempel vil array1.length give os 7, fordi der er syv elementer i det. Indekset for hver er imidlertid 0, 1, 2, 3, 4, 5 og 6. Så for at begynde ved elementet med et indeks på 6, ville vi være nødt til at tage længden af ​​arrayet og trække 1 .

At udskrive vores fulde til loop får vi:

for (var i = arr.length - 1; i> = 0; i--)

Med andre ord fratrækker vi 1 fra indekset med hver løkke, indtil i er større end eller lig med 0, starten af ​​arrayen. (Brug af arr som parameternavn i nedenstående funktion er det samme som at bruge array. Lad ikke det smide dig!)

funktion reverseArray (arr) {
  var newArray = [];
  for (var i = arr.length - 1; i> = 0; i--) {
    newArray.push (arr [i]);
  }
  returnere newArray;
}

arr [i] repræsenterer hvert element ved dets respektive indeks. På den første loop igennem er arr [i] elementet "if". På hver loop bruger vi .push () -metoden til bogstaveligt talt 'skubbe' arr [i] til slutningen af ​​den nye array.

Overførende array1 til denne funktion, får vi:

reverseArray (matrix1)
⊳ ["hvis", "aldrig", "undertiden", "altid", "måske", "nej", "ja"]

At vende et array på plads

Ting bliver straks mere kompliceret for mig, når jeg prøver at vende et array på stedet. Da jeg oprindeligt prøvede at arbejde igennem dette problem forsøgte jeg at få fat i det første element ved hjælp af .shift (), indstille det til en variabel, der blev navngivet først, og derefter bruge .push () for at tilføje det til slutningen af ​​den originale matrix. Men problemet, jeg løb ind i, er, at jeg bare vendte de første og sidste elementer om og om igen med hver løkke, fordi .shift () kun fjerner elementer ved 'zeroeth index' og .pop () til sidst.

Der var også problemet med, hvor man skulle starte og afslutte for-loop.

Før vi går videre, lad os dog skrive problemet ud i pseudokode:

// 1) Jeg ved, at jeg er nødt til at gå igennem matrixen. Men inden jeg finder ud af, hvor jeg skal starte eller slutte, er jeg nødt til at tænke over, hvordan jeg rent faktisk vil vende elementerne i arrayet.
// 2) Den eneste måde, jeg kan tænke på at gøre, er at skifte det første element med det sidste element, derefter det andet element med det andet til sidste element osv., Indtil jeg når midten.

Så hvad angår vores for loop, kan jeg starte i begyndelsen eller slutningen af ​​matrixen og afslutte, når jeg er halvdelen af ​​længden af ​​arrayet.

Den måde, jeg oprindeligt tænkte at gøre dette på, var:

for (var i = 0; i <= (arr.length / 2); i ++)

Derefter indstiller jeg det første element lig med en variabel kaldet el, sætter derefter det første element lig med det sidste og det sidste lig med det første (el).

Sådan ser det ud:

lad el = arr [i];
arr [i] = arr [arr.length - 1 - i];
arr [arr.length - 1 - i] = el;

Så med hver sløjfe nulstilles el til at svare til det næste element i arrayet.

arr [arr.length - 1 - i] er bare en måde at sige:

  1. På den første sløjfe er indekset længden på arrayen, minus 1 minus minus værdien af ​​i, som er 0. Brug af array1 som eksempel, ville det være: 8 - 1 - 0 = 7. arr [7] er det sidste element i array1, som er "hvis".
  2. På den anden sløjfe ville det være: 8 - 1 - 1 = 6. Arr [6] vil derfor være det næst-sidste element i array1, som er "aldrig". Til og med indtil man når midten af ​​matrixen.

Forsøg på det på denne måde ser ud som:

funktion reverseArrayInPlace (arr) {
  for (var i = 0; i <= (arr.length / 2); i ++) {
      lad el = arr [i];
      arr [i] = arr [arr.length - 1 - i];
      arr [arr.length - 1 - i] = el;
  }
  retur arr;
}

Men når man tester dette, sker der noget underligt med arrays, der har en jævn længde, såsom array2:

reverseArrayInPlace (matrix2)
⊳ [1, 3, 6, 9, 5, 2, 8, 5]

9 og 5 vendes i midten!

I tilfælde, hvor vores array er et ulige tal, som array1, ville brug af i <= (arr.length / 2) fungere, fordi array1.length er 3,5, og loopen vil fortsætte, så længe jeg er mindre end eller lig med 3,5 . Men hvis vores længde er 8, som det er i matrix2, stopper loopen ved indeks 4, som faktisk er 1 indeks forbi, hvor vi vil stoppe. Fordi indekset starter ved 0, vil vi faktisk stoppe ved 3.

For at løse dette kan vi trække 1 fra længden af ​​arrayet, inden vi deler det med 2. For godt mål kan vi kaste Math.floor foran til runde decimaler ned til det nærmeste hele tal.

funktion reverseArrayInPlace (arr) {
  for (var i = 0; i <= Math.floor ((arr.length - 1) / 2); i ++) {
      lad el = arr [i];
      arr [i] = arr [arr.length - 1 - i];
      arr [arr.length - 1 - i] = el;
  }
  retur arr;
}

At bedømme:

  • Vi startede i begyndelsen af ​​matrixen i vores for loop.
  • Vi bevægede os gennem matrixen, indtil vi nåede halvvejs punktet.
  • Med hver løkke indstiller vi elementet til i - eller arr [i] - lig med en variabel kaldet el.
  • Derefter sætter vi det første element lig med det sidste, og det sidste element lig med det første.
  • Med hver efterfølgende løkke, da vi flyttede indad, gjorde vi den samme ting.

Jeg er en JavaScript-rookie, så hvis du har en mere effektiv måde at gøre dette på, vil jeg meget gerne høre fra dig i kommentarfeltet nedenfor!

funktion letsConnect (ja) {
  hvis (ja === sandt) {
    console.log ( "LinkedIn");
    console.log ( "Twitter");
  } andet {
    console.log ("tak for at have læst!");
  }
}