我有一个元素数组,其中条目稀疏。如何轻松地将稀疏数组压缩成密集数组,这样每次循环数据时就不必一直检查空值和未定义值?
以下是一些示例数据:
var sparse = [];
sparse[1] = undefined;
sparse[5] = 3;
sparse[10] = null;
var dense = sparseToDenseArray(sparse);
// dense should be [3]
我有一个元素数组,其中条目稀疏。如何轻松地将稀疏数组压缩成密集数组,这样每次循环数据时就不必一直检查空值和未定义值?
以下是一些示例数据:
var sparse = [];
sparse[1] = undefined;
sparse[5] = 3;
sparse[10] = null;
var dense = sparseToDenseArray(sparse);
// dense should be [3]
您可以使用filter()
与 Firefox、Chrome、IE 9、Opera 和 Safari 网络浏览器兼容的版本。
根据 David Flanagan 的说法,在Javascript: The Definitive Guide中,将稀疏数组转换为密集数组的一种简单方法是在其上使用过滤器,如下所示:
var dense = sparse.filter(function (x) { return x !== undefined && x != null; });
这是有效的,因为它会filter()
跳过丢失的元素,并且仅true
在 x 不是undefined
or时才返回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]);
在 ES2017 (ES8) 中,这很简单Object.values(sparseArray)
例如:
const sparseArray = [, , 'foo', 'bar', , 'baz', ,];
const compactArray = Object.values(sparseArray);
console.log(compactArray);
请注意,此方法仅删除gaps,根据需要向下移动现有数组元素的索引。它不会删除显式设置为undefined
or的元素null
。
在 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]
如果你想在你的代码中包含 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");
filter 是 ECMA-262 标准的 JavaScript 扩展;因此,它可能不会出现在该标准的其他实现中。您可以通过在脚本开头插入以下代码来解决此问题,允许在本机不支持它的 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;
});