Конденсировать разреженный массив в Javascript?
У меня есть массив элементов, где записи редки. Как я могу легко сжать разреженный массив в плотный массив, чтобы мне не приходилось постоянно проверять нулевые и неопределенные значения каждый раз, когда я перебираю данные?
Вот некоторые примеры данных:
var sparse = [];
sparse[1] = undefined;
sparse[5] = 3;
sparse[10] = null;
var dense = sparseToDenseArray(sparse);
// dense should be [3]
7 ответов
В vanilla JS работает на всех браузерах:
function filt(a) {
var b = [];
for(var i = 0;i < a.length;i++) {
if (a[i] !== undefined && a[i] != null) {
b.push(a[i]);
}
}
return b;
}
> filt([1,undefined,3])
[1, 3]
В ES6 это так же просто, как Object.values(sparseArray)
Например:
const sparseArray = [, , 'foo', 'bar', , 'baz', ,];
const compactArray = Object.values(sparseArray);
console.log(compactArray);
Обратите внимание, что этот метод только удаляет пробелы, сдвигая индексы существующих элементов массива по мере необходимости. Он не удаляет элементы, явно установленные в undefined
или же null
,
Ты можешь использовать filter()
который совместим с браузерами Firefox, Chrome, IE 9, Opera и Safari.
По словам Дэвида Фланагана, в Javascript: "Полное руководство" простой способ преобразования разреженного массива в плотный массив заключается в использовании фильтра для него следующим образом:
var dense = sparse.filter(function (x) { return x !== undefined && x != null; });
Это работает с filter()
пропускает пропущенные элементы и возвращает только true
если х не undefined
или же null
,
Если filter()
не поддерживается, это сожмет разреженный массив:
var compacted = [];
for(var i = 0; i < sparse.length; i++)
if(i in sparse)
compacted.push(sparse[i]);
Точный эквивалент filter()
Пример:
var compacted = [];
for(var i = 0; i < sparse.length; i++)
if(sparse[i] != null)
compacted.push(sparse[i]);
Если вы хотите включить underscore.js в свой код, вы можете использовать функцию compact в вашем массиве.
Я не могу поверить, что здесь так мало ответов. Прежде всего, я думаю, что есть лучшие, более быстрые решения для сжатия разреженного массива. Я предполагаю, что разреженный массив не означает массив с отверстиями неопределенных элементов ( Что такое плотный массив?). Разреженный массив должен быть массивом, в котором фактически не существует ключей, кроме ключей, которые принадлежат существующим, но разреженным значениям. Поэтому, если мы перебираем ключи, мы должны делать свою работу более эффективно и быстрее.
Хорошо, я скомпилировал тест ниже, чтобы показать вам производительность нескольких методов для сжатия разреженного массива.
var ts = 0,
te = 0,
sparse = new Array(10000000),
dense = [];
[sparse[2499999], sparse[4999999], sparse[9999999]] = ["first one", "middle one", "last one"];
ts = performance.now();
dense = Object.keys(sparse).map(k => sparse[k]);
te = performance.now();
console.log(dense, "Okeys and map resulted in :" +(te-ts)+ "msecs");
dense = [];
ts = performance.now();
for (var key in sparse) dense.push(sparse[key]);
te = performance.now();
console.log(dense, "for in loop resulted in :" +(te-ts)+ "msecs");
dense = [];
ts = performance.now();
dense = sparse.filter(function (x) { return x !== undefined && x !== null; });
te = performance.now();
console.log(dense, "Array filter resulted in :" +(te-ts)+ "msecs");
dense = [];
ts = performance.now();
for (var i = 0, len = sparse.length; i < len; i++) sparse[i] !== undefined &&
sparse[i] !== null &&
dense.push(sparse[i]);
te = performance.now();
console.log(dense, "For loop resulted in :" +(te-ts)+ "msecs");
фильтр является расширением JavaScript к стандарту ECMA-262; как таковой он может не присутствовать в других реализациях стандарта. Вы можете обойти это, вставив следующий код в начало ваших сценариев, позволяя использовать фильтр в реализациях ECMA-262, которые изначально не поддерживают его. Ссылка: MDN.
Кросс-браузерное решение с использованием filter
if (!Array.prototype.filter) { // Add the filter method to the 'Array prototype' if it's not available
Array.prototype.filter = function(fun /*, thisp*/) {
var len = this.length >>> 0;
if (typeof fun != "function") {
throw new TypeError();
}
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this) {
var val = this[i];
if (fun.call(thisp, val, i, this)) {
res.push(val);
}
}
}
return res;
};
}
var sparse = [];
sparse[1] = undefined;
sparse[5] = 3;
sparse[10] = null;
dense=sparse.filter(function(a){ //Call the `filter` method
return a!== undefined && a != null;
});