Конденсировать разреженный массив в 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;
});

DEMO.

Array.from(sparse) удалит все пустые ячейки элементов.

Другие вопросы по тегам