в JS anArray = [] работает, но abArray.splice (0, anArray.length) и anArray.length = 0 дают неверные результаты в следующем коде: - PullRequest
1 голос
/ 26 октября 2019

У меня есть несколько версий простого вложенного цикла for во вложенном коде. Я хотел бы повторно использовать один и тот же массив для каждой итерации цикла, а не создавать новый массив для каждой итерации, поскольку, очевидно, это заняло много памяти и создает избыточный мусор для сбора.

Результатом этого кода должен быть массив массивов, который содержит подмножество данного большего массива массивов. Один и тот же простой код работает по-разному в зависимости от метода, который я использую для очистки промежуточного одномерного массива во внешнем цикле для его повторного использования. В частности, anArray=[] работает для очистки anArray, но и anArray.length=0, и anArray.splice(0, anArray.length) дают неверные результаты в моем коде.

Я знаю, как заставить это работать, и я знаю, как его кодировать «лучше». Это было извлечено из функций внутри сложного кода, чтобы изолировать то, что кажется ошибкой. Я хочу знать, почему 2-й и 3-й примеры не работают должным образом?

Раскрытие информации: я написал много C и ассемблера для DSP, но у меня нет опыта работы с JavaScript. Пожалуйста, просветите меня! Какие знания мне не хватает, что сделало бы эти результаты понятными?

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

Код, который работает так:

var sets = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60],
  [100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays. 
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.

for (var i = 0; i < 3; i++) {
  singleSubset = []; // clear this array each outer iteration so we can use .push
  for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
    singleSubset.push(sets[i][di])
  };
  arrayOfSubsets.push(singleSubset); // push each subset array on to the output array of arrays.                
}

for (j = 0; j < 3; j++) {
  console.log(arrayOfSubsets[j]);
} // display result:

[2, 3, 4, 5]
[20, 30, 40, 50]
[200, 300, 400, 500]

Это, как и ожидалось, правильно.

Вот очень похожий код с использованием .length = 0, который не работает:

var sets = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60],
  [100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays. 
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.

for (var i = 0; i < 3; i++) {
  singleSubset.length = 0; // clear this array each outer iteration so we can use .push
  for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
    singleSubset.push(sets[i][di])
  };
  arrayOfSubsets.push(singleSubset); // push each subset array on to the output array of arrays.                
}

for (j = 0; j < 3; j++) {
  console.log(arrayOfSubsets[j]);
} // display result:

[200, 300, 400, 500]
[200, 300, 400, 500]
[200, 300, 400, 500]

Это явно не ожидается и не правильно.

Вот версия, в которой не используется .push, поэтому промежуточный массив не нужно очищать междуитераций. Тем не менее, метод = [] работает, и на самом деле все еще требуется, или это не работает правильно. Попробуйте этот код с каждым из различных методов очистки, откомментировав при необходимости:

var sets = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60],
  [100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays. 
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.

for (var i = 0; i < 3; i++) {
  singleSubset = []; // works and is required or it doesn't work.  But comment it out and try:
  // singleSubset.length = 0;  // or try:
  // singleSubset.splice(0, singleSubset.length);  // or for extra madness try:
  // singleSubset.length = 0; singleSubset = []; // as placing .length=0 ahead of =[] produces bad output too! 
  for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
    singleSubset[di - subsetBounds[0]] = sets[i][di];
  }
  arrayOfSubsets[i] = singleSubset;
}

for (j = 0; j < 3; j++) {
  console.log(arrayOfSubsets[j]);
} // display result:

[200, 300, 400, 500]
[200, 300, 400, 500]
[200, 300, 400, 500]

Это явно не ожидается и не правильно.

Опция .length=0, предшествующая =[], приводит к следующему:

[]
[]
[200, 300, 400, 500]

Имеет ли это какое-либо значение для кого-либо? Я с нетерпением жду того, как многомерные массивы будут выражаться в C. Намного проще понять! И конечно, если извлечение подмножества двумерного массива в виде меньшего двумерного массива можно сделать одним оператором с использованием более качественного JS, я тоже за это благодарю.

Ответы [ 2 ]

1 голос
/ 26 октября 2019

Если вы не создаете новый массив каждый раз через цикл, все элементы arrayOfSubsets будут ссылками на один и тот же массив. Когда вы изменяете его длину, соединяете его или вставляете в него новые элементы, все они получают эти изменения.

Так что вам нужно либо создавать новый массив каждый раз в цикле (это нормальный способ)или сделайте копию, когда вы поместите ее в содержащий массив:

arrayOfSubset.push(singleSubset.slice());
1 голос
/ 26 октября 2019

Когда вы используете singleSubset = [];, вы создаете новый массив. Когда вы используете singleSubset.length = 0; или singleSubset.splice(0, singleSubset.length);, вы обновляете временный массив, который вы уже назначили. Это означает, что любое изменение будет отражено на всех ваших подмножествах.

В этом случае singleSubset.length = 0; singleSubset = []; вы очищаете ранее назначенный массив, а затем генерируете новый. Это означает, что первые два подмножества будут пустыми.

Как бы я это сделал - используйте Array.map(), чтобы выполнить итерацию sets и создать новый массив. Используйте slice в каждом подмножестве, потому что slice возвращает новый массив.

const sets = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60],
  [100, 200, 300, 400, 500, 600]
]

const subsetBounds = [1, 5];

const result = sets.map(subset => subset.slice(...subsetBounds));

console.log(result);
...