NodeJS как ускорить эту функцию создания массива

#javascript #arrays #node.js #function #object

#javascript #массивы #node.js #функция #объект

Вопрос:

Было сложно дать ей хорошее название, чтобы описать, что это такое, но это лучшее, что я придумал. В любом случае, это просто создает колоду карт, а затем удаляет закрытые карты. Производительность имеет решающее значение, поскольку требуется выполнить тысячи итераций создания этой новой колоды, перетасовки и удаления закрытых карт.

Создание колоды происходит очень быстро, но функция удаления закрытых карт сильно снижает производительность, поскольку я не могу найти простого способа удалить элемент в 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; }  

Комментарии:

1. Если ваши костюмы всегда будут одинаковыми, то было бы еще быстрее избежать цикла и жестко закодировать массив. И если карты для удаления также будут одинаковыми каждый раз, тогда вы можете просто удалить их из этого жестко запрограммированного массива, чтобы не повторять цикл по всей колоде по крайней мере дважды.

2. Масти и колода всегда будут одинаковыми, но не закрытые карты. Это для сравнения закрытых карт друг с другом, чтобы определить, кто сколько раз выигрывает и т.д.

Ответ №1:

Поскольку deck должен быть массив, вам определенно не следует перебирать его Object.keys — скорее, поскольку все значения массива являются примитивами, вы можете идентифицировать индекс с помощью indexOf и splice , или установить для элемента с индексом этого массива значение null , если это то, что вы хотите:

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

(установка индекса на null фактически не удаляет элемент из массива, поэтому я думаю, что вы, возможно, имели в виду, что хотели splice вместо этого)

 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;
}  

Ответ №2:

Если параметры не собираются меняться, то, безусловно, самый быстрый способ создать это — не создавать цикл, просто жестко запрограммировать массив:

 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', 
  ];
}
  

Если карты, которые необходимо удалить, всегда будут одинаковыми, тогда вы можете просто исключить их из этого жестко запрограммированного массива.

 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', 
  ];
}
  

Это позволяет избежать многократного перебора колоды. Итак, весь код, с которым вы остались, это:

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

Если вместо этого карты для удаления являются динамическими, их проще исключить при создании колоды, вместо того, чтобы искать их после, таким образом, вы перебираете колоду только один раз — при создании:

 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;
}  

Это может быть еще быстрее, если remove это был объект { '10s': true, '11s': true, '13h': true, '9c': true }; или набор new Set(['10s', '11s', '13h', '9c']) . В любом случае при поиске не нужно было бы перебирать весь массив для каждой сгенерированной вами карты.

Комментарии:

1. Закрытые карты будут меняться каждый раз, но жесткое кодирование всей колоды действительно немного быстрее. Странно, я просмотрел так много программ-калькуляторов карт на php, python и javascript, и никто никогда не делал этого. Я также рассмотрю возможность удаления объекта и посмотрю, как это происходит. Спасибо за вашу помощь, вы, кажется, много знаете об оптимизации скорости в коде.

2. Я перепробовал все ваши предложения, и самым быстрым был жестко закодированный набор с оригинальной функцией удаления. Не уверен почему, но удаление как объекта, выполняемое if (!remove[card]) для удаления его при создании колоды, было самым медленным. Удаление ее с помощью deck creation с помощью remove as an array было быстрее, чем удаление ее после, но все же жестко закодированная колода была еще быстрее.

Ответ №3:

deck это массив, поэтому вам не нужно Object.keys :

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