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

时间:2019-01-26 23:53:25

标签: javascript arrays pointers multidimensional-array

我正在使用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];
  }
});
});

4 个答案:

答案 0 :(得分: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 :(得分: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";

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

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

import { set } from 'lodash';

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

答案 2 :(得分:0)

假设libVars中的路径与lib中的路径相同,那么您只需将更改记录到一系列函数中,然后在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);

答案 3 :(得分:0)

这可以使用代理通过模拟自动生存来处理。参见:

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

Autovivification and Javascript