简体   繁体   中英

NodeJS how to speed up this array creation function

It was hard to give it a good title to describe what this is but that's the best I came up with. Anyway, this simply creates a deck of cards and then removes the hole cards. Performance is crucial since it needs to make thousands of iterations of this new deck creation, shuffle and hole card removal.

It's very fast to create the deck but the hole card removal function has a huge performance hit since I can't find any easy way to remove an element in JS.

 const suits = ['s', 'h', 'd', 'c']; const remove = ['10s', '11s', '13h', '9c']; var deck = mkDeck(); shuffle(deck) rmvHole(); // Functions function rmvHole() { for (let i = 0; i < remove.length; i++) { const key = Object.keys(deck).find(key => deck[key] === remove[i]); deck[key] = null; } } function mkDeck() { let arr = []; for (let s = 0; s < 4; s++) { for (let i = 2; i < 15; i++) { arr.push(i + suits[s]); } } return arr; } function shuffle(a) { for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; } console.log(deck);
 .as-console-wrapper { max-height: 100% !important; top: auto; }

Since deck should be an array, you definitely shouldn't iterate over its Object.keys - rather, since the array values are all primitives, you can identify the index with indexOf and splice , or set the item at that array index to null if that's what you want:

function rmvHole() {
    for (let i = 0, { length } = remove; i < length; i++) {
        const index = deck.indexOf(remove[i]);
        // deck.splice(index, 1);
        // deck[index] = null;
    }
}

(setting an index to null doesn't actually remove the element from the array, which is why I'm thinking you might have meant you wanted to splice instead)

 const suits = ['s', 'h', 'd', 'c']; const remove = ['10s', '11s', '13h', '9c']; var deck = mkDeck(); shuffle(deck) rmvHole(); // Functions function rmvHole() { for (let i = 0; i < remove.length; i++) { const index = deck.indexOf(remove[i]); deck[index] = null; } } function mkDeck() { let arr = []; for (let s = 0; s < 4; s++) { for (let i = 2; i < 15; i++) { arr.push(i + suits[s]); } } return arr; } function shuffle(a) { for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; } console.log(deck);
 .as-console-wrapper { max-height: 100% !important; top: auto; }

If the suits are not going to change, then by far the fastest way to create this is to not have a loop, simply hard-code the array:

function mkDeck() {
  return [
      '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', '10s', '11s', '12s', '13s', '14s', 
      '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', '10h', '11h', '12h', '13h', '14h', 
      '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', '10d', '11d', '12d', '13d', '14d', 
      '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', '10c', '11c', '12c', '13c', '14c', 
  ];
}

If the cards that need to be removed are always going to be the same, then you can simply exclude them from that hard-coded array.

function mkDeck() {
  return [
      '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s',               '12s', '13s', '14s', 
      '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', '10h', '11h', '12h',        '14h', 
      '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', '10d', '11d', '12d', '13d', '14d', 
      '2c', '3c', '4c', '5c', '6c', '7c', '8c',       '10c', '11c', '12c', '13c', '14c', 
  ];
}

This cuts out looping over the deck several times. So all the code you're left with is:

let deck = mkDeck();
shuffle(deck);

If instead the cards for removal are dynamic, it's easier to exclude them when generating the deck, instead of looking for them after, this way you only loop over the deck once - when generating:

 const suits = ['s', 'h', 'd', 'c']; const remove = ['10s', '11s', '13h', '9c']; var deck = mkDeck(); console.log(deck); function mkDeck() { let arr = []; for (let s = 0; s < 4; s++) { for (let i = 2; i < 15; i++) { let card = i + suits[s]; //only add if it should be added if (!remove.includes(card)) { arr.push(card); } } } return arr; }

This can be even faster if remove was an object { '10s': true, '11s': true, '13h': true, '9c': true }; or a set new Set(['10s', '11s', '13h', '9c']) . In either case, the lookups would not need to iterate over the entire array for each card you generate.

deck is an array, so you don't need Object.keys :

function rmvHole() {
    remove.forEach(r => deck.splice(deck.indexOf(r), 1));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM