稀疏数组处理
稀疏数组是指数组中大部分元素为空或默认值的数组。处理稀疏数组时需要注意性能和内存占用问题,JavaScript提供了多种方法来优化这类场景。
稀疏数组的特性
稀疏数组在JavaScript中表现为包含"空洞"的数组,通过in
运算符可以检测索引是否存在:
const sparseArr = [1, , 3]; // 索引1的位置是空洞
console.log(1 in sparseArr); // false
console.log(sparseArr.length); // 3
使用Array.from()
创建数组时会保留空洞:
const arr = Array.from({length: 5});
console.log(arr); // [undefined, undefined, undefined, undefined, undefined]
检测稀疏数组
可以通过比较length
和实际元素数量来判断:
function isSparse(arr) {
return arr.length !== Object.keys(arr).length;
}
const dense = [1,2,3];
const sparse = [1,,3];
console.log(isSparse(dense)); // false
console.log(isSparse(sparse)); // true
遍历方法差异
不同数组方法处理稀疏数组的方式不同:
const sparse = [1, , 3];
// forEach会跳过空洞
sparse.forEach(item => console.log(item)); // 1, 3
// map会保留空洞
const mapped = sparse.map(x => x * 2); // [2, empty, 6]
// filter会移除空洞
const filtered = sparse.filter(Boolean); // [1, 3]
性能优化技巧
处理大型稀疏数组时需要注意性能:
- 使用
for...of
循环比传统for
循环更快:
const largeSparse = new Array(1e6);
largeSparse[999] = 'value';
// 较慢的方式
for (let i = 0; i < largeSparse.length; i++) {
if (i in largeSparse) {
console.log(largeSparse[i]);
}
}
// 较快的方式
for (const item of largeSparse) {
if (item !== undefined) {
console.log(item);
}
}
- 使用
Object.keys()
获取有效索引:
const validIndices = Object.keys(sparse).map(Number);
validIndices.forEach(i => {
console.log(sparse[i]);
});
实际应用场景
- 棋盘类游戏的状态存储:
// 使用稀疏数组存储棋盘状态
const chessBoard = new Array(8);
for (let i = 0; i < 8; i++) {
chessBoard[i] = new Array(8);
}
// 只存储有棋子的位置
chessBoard[0][0] = '♜';
chessBoard[0][7] = '♜';
chessBoard[7][0] = '♖';
- 时间序列数据压缩:
// 原始数据
const timeSeries = [];
for (let i = 0; i < 24; i++) {
timeSeries.push(null); // 每小时一个槽位
}
// 只记录有数据的时间点
timeSeries[9] = {value: 42, unit: '°C'};
timeSeries[15] = {value: 38, unit: '°C'};
// 转换为紧凑格式
const compact = timeSeries
.map((val, idx) => val !== null ? {time: idx, data: val} : null)
.filter(Boolean);
与密集数组的转换
- 稀疏转密集:
function toDense(sparse) {
return [...sparse].filter(item => item !== undefined);
}
const sparse = [1, , , 4];
const dense = toDense(sparse); // [1, 4]
- 密集转稀疏(按需):
function toSparse(dense, length) {
const sparse = new Array(length);
dense.forEach((item, i) => {
sparse[i] = item;
});
return sparse;
}
const dense = [1, 2, 3];
const sparse = toSparse(dense, 5); // [1, 2, 3, empty × 2]
内存管理注意事项
处理超大型稀疏数组时:
// 错误方式 - 会实际分配内存
const badHugeArray = new Array(1e8); // 立即分配内存
// 正确方式 - 使用Proxy延迟分配
const hugeArray = new Proxy({}, {
get(target, prop) {
if (prop === 'length') return 1e8;
return prop in target ? target[prop] : undefined;
},
set(target, prop, value) {
target[prop] = value;
return true;
}
});
hugeArray[999999] = 'value'; // 只存储实际使用的索引
类型化数组的稀疏处理
类型化数组不支持真正的稀疏性,但可以模拟:
// 使用最大值表示"空"
const typedArray = new Int32Array(10).fill(Number.MAX_SAFE_INTEGER);
typedArray[3] = 42;
typedArray[7] = 24;
function getTypedSparseValues(arr, emptyValue) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== emptyValue) {
result.push(arr[i]);
}
}
return result;
}
const values = getTypedSparseValues(typedArray, Number.MAX_SAFE_INTEGER);
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn