Javascript - 链接到更大数组的值数组

问题描述 投票:1回答:4

我正在使用Javascript并创建一个离线应用程序。

我有一个非常大的阵列,超过10mb。我需要从用户进行更改的数组中保存元素,但是将数组写入/读取到磁盘的速度太慢。

我想创建一个仅保存用户所做更改的第二个数组,因此我可以保存该较小的数组,然后当我需要加载更改时,它可以将其更改镜像到大数组。

例如:

lib[x][1][y][6] = "no";
libVars[x][1][y][6] = "no";

libVars将简单地保存lib中的元素更改,并且与大型数组lib的大小不同,因为用户只会与大型数组的一小部分进行交互。

显然这不起作用,因为libVars没有与lib相同的结构,如果它这样做也会占用大量的内存(我想也是如此!)

然后我想循环遍历libVars并在libVars中保存更改的相同元素点更新lib。

有没有办法将一些类型的指针保存到lib中的一个位置,我可以在libVars中存储相关的元素值?

任何帮助将非常感激。

谢谢。

======================

我的大阵列样本

var lib = [
[241,[[221119,"sample data","sample","no","no",131,"no"],
[221121,"sample2 data","sample2","no","no",146,"no"],
[221123,"sample3 data","sample3","no","no",28,"no"],
[221626,"sample4 data","sample4","no","no",26,"no"],
[221628,"sample5 data","sample5","no","no",88,"no"]]],
[330,[[305410,"2sample data","sample 2b","no","no",197,"no"],
[305412,"2sample 2 data","sample2 2b","no","no",147,"no"],
[305414,"3sample 2 data","sample3 2b","no","no",10,"no"] ... 

尝试解决Z-Bone发布的解决方案

我添加了tempLib var,但是我没看到你最终如何更新实际的lib对象

Object.entries(libVars).forEach(([path, value]) => {

  var tempLib = lib;
  var pathParts = path.split('#');

  pathParts.forEach((pathPart, index) => {

  if (index == pathParts.length-1) {

    tempLib[pathPart] = value;

  } else {
    //I don't fully track what you are doing here. 
    //I assume you are building the array path, but to me it looks like
    // it's getting wiped out and not built upon?    
    tempLib = tempLib [pathPart];
  }
});
});
javascript arrays pointers multidimensional-array
4个回答
2
投票

更新28/01/2019基于nomaam的测试数据

@nomaam请检查以下代码段。我让它改变了lib数组中的任意路径。我选择的路径是:lib[0][1][3][4]。您可以看到它最初如何返回值"no",然后在执行修改跟踪解决方案后,它返回值"yes"

// First Step: Original Data (lib)
var lib = [
[241,[[221119,"sample data","sample","no","no",131,"no"],
[221121,"sample2 data","sample2","no","no",146,"no"],
[221123,"sample3 data","sample3","no","no",28,"no"],
[221626,"sample4 data","sample4","no","no",26,"no"],
[221628,"sample5 data","sample5","no","no",88,"no"]]],
[330,[[305410,"2sample data","sample 2b","no","no",197,"no"],
[305412,"2sample 2 data","sample2 2b","no","no",147,"no"],
[305414,"3sample 2 data","sample3 2b","no","no",10,"no"]]]]

// Log initial value in arbitrary selection lib[0][1][3][4]
console.log(lib[0][1][3][4])

// Second Step: Pointer's object
var libVars = {}

// Example of changing a value via an artificial "pointer" to lib[0][1][3][4]
libVars['0#1#3#4'] = 'yes'; // original value is "no"

// Third Step: Run the modifier - update changes from libVars to lib
Object.entries(libVars).forEach(([path, value]) => {

  var tempLib = lib;
  var pathParts = path.split('#');
  
  pathParts.forEach((pathPart, index) => {
    
    if (index == pathParts.length - 1) {
      
      tempLib[pathPart] = value;
      
    } else {
      
      tempLib = tempLib[pathPart];
      
    }
  });
});


// Log the change fro lib
console.log(lib[0][1][3][4])

原始答案

如果我正确理解了您的挑战,您可以在技术上持有一个对象,其中包含要修改的属性的路径作为键,修改后的值作为其值。

假设您的原始对象如下所示:

var lib = {a: {b: { c: { d: "yes"}}}}

您可以在备份对象中保留更改日志(例如,值从“是”更改为“否”)。它可能看起来像这样,.标记一个嵌套属性。

var libVars = {};
libVars['a.b.c.d'] = "no";

然后,当您想要更新原始的大型数组/值对象时,您可以这样做:

Object.entries(libVars).forEach(([path, value]) => {
    var tempLib = lib;
    // split by nesting indicator -> dot
    var pathParts = path.split('.');
    // iterate all parts of the path to the modified value
    pathParts.forEach((pathPart, index) => {
        if (index == pathParts.length-1) {
            // once you made your way to last index, update value
            tempLib[pathPart] = value;
        } else {
            tempLib = tempLib[pathPart];
        }
    })
})

console.log(lib); // outputs => {a: {b:{c: {d : "no"}}}}

1
投票

更新2

更新了我的答案,摆脱lodash,它似乎等于Z-Bone的答案。他的变体比我的更清晰。

更新于@ 28.01.2019

var lib = [
[241,[[221119,"sample data","sample","no","no",131,"no"],
[221121,"sample2 data","sample2","no","no",146,"no"],
[221123,"sample3 data","sample3","no","no",28,"no"],
[221626,"sample4 data","sample4","no","no",26,"no"],
[221628,"sample5 data","sample5","no","no",88,"no"]]],
[330,[[305410,"2sample data","sample 2b","no","no",197,"no"],
[305412,"2sample 2 data","sample2 2b","no","no",147,"no"],
[305414,"3sample 2 data","sample3 2b","no","no",10,"no"]]]];

// object to track edits
var edits = {
  '0.1.2.2': 'edited'
};

// sample/simple implementation of lodash's 'set' function
function applyEdit(arr, path, value) {
  var items = path.split('.');
  var last = items.length - 1;
  var current = arr;
  items.forEach(function (item, i) {
    if (i !== last) {
      current = current[item];
    }
  });
  current[items[last]] = value;
}

// our restoration function
function patch(arr, edits) {
  Object.keys(edits).forEach(function(key) {
    var newValue = edits[key];
    applyEdit(arr, key, newValue);
  });
}

console.log(lib[0][1][2][2]) // "sample3"

// now we can restore our edits
patch(lib, edits);

console.log(lib[0][1][2][2]) // "edited"

// --------------------------------------------------------

// to prevent forgetting to track the updates you can use utility function
// to make changes to your 'lib' array

function update(arr, path, value) {
  applyEdit(arr, path, value);
  edits[path] = value;
}


原始答案:

一种可能的解决方案是拥有一个跟踪所有更改的对象。 const edits = {};当你用lib[x][1][y][6] = "no";更新你的对象时,你也保存你的编辑:

edits[`${x}.1.${y}.6`] = "no";

基本上,您只需创建一个包含更改路径的字符串。

从文件加载编辑对象后,可以使用以下代码将所有更改应用于原始数组:

import { set } from 'lodash';

function patch(arr, edits) {
  Object.keys(edits).forEach(key => {
    const newValue = edits[key];
    set(arr, key, newValue);
  });
}

0
投票

假设libVarslib中的路径相同,那么您可以简单地将更改记录到稍后在lib对象上重新应用的函数数组中:

const data = {foo: 'aaa', bar: 'bbb'};

console.log('data before:', data);

const updates = [];

updates.push(obj => {
  obj.foo = 'foo';
});

updates.push(obj => {
  obj.bar = 'bar';
});

updates.forEach(fn => fn(data));

console.log('data after:', data);

0
投票

这可以使用代理模拟自动生成来处理。看到:

https://en.wikipedia.org/wiki/Autovivification

Autovivification and Javascript

© www.soinside.com 2019 - 2024. All rights reserved.