javascript - Sett inn på spesifikt indeks i en Map


Som dokumentasjonen for Map sier:

Nøklene i Map er ordnet, mens nøkler lagt til i objektet ikke er det. Dermed, når man itererer over det, returnerer et Map-objekt nøkler i rekkefølgen de ble lagt til.

For å utnytte dette fullt ut, trenger jeg å sette inn et element i en Map på en gitt spesifikk rekkefølge.

Jeg vet dette kan gjøres med et array, men jeg foretrekker å bruke en Map fordi jeg trenger å gjøre mange oppslag etter nøkkel, og en Map fungerer godt for det tilfellet, samtidig som den er lett å vedlikeholde.

Jeg kom opp med noe sånt, og jeg vil gjerne vite om det finnes noen bedre måter å gjøre det på.

  function insertAtIndex(index, key, value, map){
    var iterator1 = map[Symbol.iterator]();
    var tmpMap = new Map();
    var tmpIndex=0;
    for (let item of iterator1) {
        if(tmpIndex === index){
            tmpMap.set(key, value);
        }
        tmpMap.set(item[0], item[1]);
        tmpIndex++;
    }
    return tmpMap;
  }

eller

  insertCardAtIndex(index: Number, key: string, value:boardCard, map:Map<string, boardCard>): Map<string, boardCard> {
    let clonedMap = new Map(map);
    let tmpMap = new Map<string, boardCard>();
    let tmpIndex = 0;

    for (let entry of Array.from(clonedMap.entries())) {
      if(tmpIndex === index){
        tmpMap.set(key, value);
      }
      tmpMap.set(entry[0], entry[1]);
      tmpIndex++;
    }

    return tmpMap;
  }

For mitt brukstilfelle vil jeg aldri måtte håndtere et kart som er stort nok til at ytelse blir en hovedbekymring, så jeg er villig til å ofre ytelse hvis det gjør koden mer lesbar og vedlikeholdbar.

Jeg bruker et kart som har en «ordbok» av verdier etter . Det faktum at det ikke finnes noen måte å sette inn et element i en bestemt rekkefølge gjør at jeg lurer på om jeg bør bruke et array i stedet, selv om det å ha raske oppslag, og metoder som .has(), .get() og .set() er veldig nyttige, men ikke verdt bryet med å ikke kunne sette inn på en bestemt indeks.

Svar #1

Du kan konvertere Map til et Array, bruke Array.splice for å sette inn elementet, og deretter konvertere tilbake til en Map. Dette er ikke en effektiv løsning, men du nevnte at vedlikeholdbarhet er viktigere enn ytelse i ditt brukstilfelle.

Denne versjonen har fordelen av å fungere hvis indeksen din er større enn størrelsen på kartet. For eksempel vil innsetting av et element på posisjon map.size + 1 fortsatt legge til elementet nederst, mens i algoritmen din ville elementet ikke blitt satt inn. Hvis du vil ignorere innsettinger som er utenfor grensen, bør det enkelt kunne løses med en sjekk i funksjonen, men dette virket mer robust.

function insertAtIndex(index, key, value, map){
  const arr = Array.from(map);
  arr.splice(index, 0, [key, value]);
  return new Map(arr);
}

const m = new Map();
m.set('0', 0);
m.set('1', 1);
m.set('2', 2);

console.log(Array.from(m.keys()));

let m2 = insertAtIndex(1, '0.5', 0.5, m);
console.log(Array.from(m2));
m2 = insertAtIndex(0, '-1', -1, m2);
m2 = insertAtIndex(5, '5', 5, m2);
m2 = insertAtIndex(10, '10', 10, m2);

console.log(Array.from(m2));

Merk at, i likhet med funksjonene i selve spørsmålet, oppretter og returnerer ovennevnte funksjon et nytt Map, noe som betyr at gamle referanser til kartet blir ugyldige etter innsetting. Dette er ok hvis du antar uforanderlighet, men hvis koden din generelt er foranderlig og du antar at referanser til kartet må forbli gyldige, må du gjøre noe som følgende:

 function insertAtIndex(index, key, value, map){
  const arr = Array.from(map);
  arr.splice(index, 0, [key, value]);
  map.clear();
  arr.forEach(([k,v]) => map.set(k,v));
}

const m = new Map();
m.set('0', 0);
m.set('1', 1);
m.set('2', 2);

console.log(Array.from(m.keys()));

insertAtIndex(1, '0.5', 0.5, m);
insertAtIndex(0, '-1', -1, m);
insertAtIndex(5, '5', 5, m);
insertAtIndex(10, '10', 10, m);

console.log(Array.from(m));

Relaterte artikler