百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

稀疏数组——前端电子表格中的应用实战

wptr33 2025-06-04 02:10 16 浏览

前文中我们详细介绍过稀疏数组的那些事儿,以及在实际项目中,稀疏数组如何在前端电子表格中发挥出它最大的效果。而这次,我们将从实战应用出发,为大家介绍稀疏数组在前端中的具体应用。

我们都知道在Javascript中是通过Array()构造函数构件稀疏矩阵,或者通过数组,设定数组的索引长度大于当前数组长度的方式来创建稀疏矩阵。

var arr = new Array(100)   //arr没有元素,但arr.length是100
var a = [];  //创建一个空数组,length为0
a[50] = 50;  //赋值添加一个元素,length为 51

稀疏数组中,没有元素的结点为empty,获取这些结点将返回结果undefined。通过使用index in array可以判断一个结点是否有元素。例如下面代码中,a[0]和a[1]的返回都为undefined,但是a[1]其实为空。

JS中已经支持稀疏数组的存储,但在实际情况中,我们保存稀疏数组的保存并不是直接进行,而是会根据实际情况构建其他存储方式保存稀疏数组。想了解为什么要“多此一举”,这里就需要大家了解一个概念——数据持久化。

我们在前端进行许多操作时,会产生许多数据,例如在前端表格进行多人填报、协同的时候,会出现很多需要长期保存的数据,有些数据还要转移到其它位置中便于人们存储、管理、操作等。而实现这一目标的关键点就是数据的持久化,我们需要将内存中数据序列化为json等存储格式保存到数据库并还能反序列化到内存。在之前的文章详解电子表格中的json数据:序列化与反序列化已经具体介绍了,大家有兴趣可以查看。

看到这里,你以为问题彻底解决了吗,图样图森破。

为了解决数据持久化,我们使用了JSON,但这时新的问题也随之出现,JSON存储中没有undefined。我们对数组进行操作的时候,数组中empty字段都会序列化为null,如下图所示。

JSON.stringify(a)
'[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,50]'

再次parse后,数组便不再是稀疏数组了。

JSON.parse(JSON.stringify(a))
(51) [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 50]

这种情况下,为了解决JSON数据在转化过程中上述出现的情况,我们就需要构建一些其他存储方式,来更好地解决这个问题~而这些存储方式又有哪些特点,让我们一起看看。

1、对象存储

在前端利用JS的语言特点,我们可以通过Object可以轻松实现Sparse Array。例如在Spread JS中,对象属性名称对应所在单元格的行列,value属性保存单元格的值,同样可以拓展出formula和style等属性保存单元格公式和样式。使用Sparse Array不用初始化大小也不用关心数据的扩容,需要做行列操作时也只需要改变行列属性的引用即可。

上图中的数据存储结果如下

{
    "0": {
        "0": {
            "value": 0
        }
    },
    "2": {
        "1": {
            "value": 2
        },
        "3": {
            "value": "S"
        }
    },
    "4": {
        "3": {
            "value": 3
        }
    }
}

需要存取数据时候直接通过对象属性访问。下面是JS Sparse Array的一个简单对象实现。

function SparseArray(){
    this._array = {}
}
SparseArray.prototype.setValue = function(row, col, data){
    if(!this._array[row]){
        this._array[row] = {}
    }
    this._array[row][col] = data
}
SparseArray.prototype.getValue = function(row, col){
    if(this._array[row]){
        return this._array[row][col]
    }
    return undefined;
}
let arr = new SparseArray();
arr.setValue(3, 3, 5);
console.log(arr.getValue(3, 3))    // 5
 
 
 

2、三元组

在矩阵中每一个元素有行标,列标,元素值三个信息,将元素按需放入数组中便是三元组存储。存储结构可以是一个包含元素信息对象,也可以直接简化为一个长度为3的数组。三元组的存储方式可以方便记录类似下图的轨迹信息或者自由曲线信息,通过对数组进行push和pop,可以方便进行回退和前进。

上图中的轨迹信息,以数组三元组存储后如下,元素value代表当前已元素数量,也可以使用对象记录时间等更多信息。

[
    [1,1,1],
    [5,8,2],
    [4,3,3],
    [1,5,4]
]

下面,我们就用这种方式建立一个undoStack记录回退。

function TSMatrix(){
this._array = [];
this.undoStack = []
}
 
TSMatrix.prototype.addNode = function(row, col, value){
this._array.push([row, col, value])
}
TSMatrix.prototype.canUndo = function(){
return this._array.length > 0;
}
TSMatrix.prototype.undo = function(){
if(this._array.length > 0){
this.undoStack.push(this._array.pop())
}
}
TSMatrix.prototype.canRedo = function(){
return this.undoStack.length > 0;
}
TSMatrix.prototype.redo = function(){
if(this._array.length > 0){
this._array.push(this.undoStack.pop())
}
}
TSMatrix.prototype.print = function(){
console.log(JSON.stringify(this._array))
}
let mat = new TSMatrix();
mat.addNode(1, 1, 1)
mat.addNode(5, 8, 2)
mat.addNode(4, 3, 3)
mat.addNode(1, 5, 4)
mat.print() //[[1,1,1],[5,8,2],[4,3,3],[1,5,4]]
mat.undo()
mat.print()  //[[1,1,1],[5,8,2],[4,3,3]]
mat.redo()
mat.print()  //[[1,1,1],[5,8,2],[4,3,3],[1,5,4]]

除了以上两种方式,还可以将上述方式结合,建立十字链表以应对更复杂的场景。大家如果感兴趣点个赞我们下次继续说。

在后续的内容中,我们还会继续为大家带来其他前端电子表格技术中的深度解密,走过路过不要错过。

相关推荐

redis的八种使用场景

前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...

基于Redis的3种分布式ID生成策略

在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...

基于OpenWrt系统路由器的模式切换与网页设计

摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...

这篇文章教你看明白 nginx-ingress 控制器

主机nginx一般nginx做主机反向代理(网关)有以下配置...

如何用redis实现注册中心

一句话总结使用Redis实现注册中心:服务注册...

爱可可老师24小时热门分享(2020.5.10)

No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...

Apportable:拯救程序员,IOS一秒变安卓

摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...

JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透

以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...

3月26日更新 快速施法自动施法可独立设置

2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...

Redis 是如何提供服务的

在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...

lua _G、_VERSION使用

到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...

China's top diplomat to chair third China-Pacific Island countries foreign ministers' meeting

BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...

移动工作交流工具Lua推出Insights数据分析产品

Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...

Redis 7新武器:用Redis Stack实现向量搜索的极限压测

当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...

Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求

重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...