Javascript — массив значений, связанный с большим массивом

Я работаю в Javascript и создаю автономное приложение.

У меня очень большой массив, более 10 МБ. Мне нужно сохранить элементы из массива, где пользователь внес изменения, но запись/чтение массива на диск происходит слишком медленно.

Я хотел бы создать второй массив, который содержит только изменения, сделанные пользователем, поэтому я могу сохранить этот меньший массив, а затем, когда мне нужно загрузить изменения, он может отразить свои изменения в большом массиве.

Например:

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

libVars будет просто хранить изменения элементов в lib и не будет иметь тот же размер, что и большой массив lib, поскольку пользователь будет взаимодействовать только с небольшой частью большого массива.

Очевидно, это не работает, так как libVars не имеет той же структуры, что и lib, а если бы она была, это также заняло бы много памяти (я так думаю в любом случае!)

Затем я хотел бы перебрать libVars и обновить lib в тех же точках элементов, где изменения были сохранены в libVars.

Есть ли способ сохранить какой-либо указатель на место в 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, но не вижу, как вы в конечном итоге обновите фактический объект 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];
  }
});
});
npmjs.com/package/json-указатель
Joe Warner 27.01.2019 01:21

@JoeWarner Спасибо, но я бы хотел избежать каких-либо библиотек.

nomaam 27.01.2019 22:08
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
118
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Обновление 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.info(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.info(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.info(lib); // outputs => {a: {b:{c: {d : "no"}}}}

Разве это не предполагает, что в имени ключа не может быть .? например {'a.b': {'c.d': 'yes'}}

customcommander 27.01.2019 01:56

@customcommander Это пример возможного подхода. Вы можете заменить точку представления вложения любым другим символом. Вы также можете избежать его, а затем разделить с помощью оператора экранирования.

Z-Bone 27.01.2019 07:56

Я пытаюсь заставить ваш пример работать. Я получаю неопределенные ошибки в разделе tempLib = tempLib[pathPart]. Мне нравится концепция. Не могли бы вы уточнить для меня, если я обычно обращаюсь к массиву, такому как lib[0][1][3][6], есть ли способ преобразовать строку без цикла, например lib[ "0,1,3, 6" ], если это возможно, то можно было бы просто вставить прямые пути к "указателям", и мне не пришлось бы беспокоиться о неопределенных ошибках или проблемах с индексацией в цикле.

nomaam 27.01.2019 22:03

Я опубликовал свою попытку вашего решения с комментариями в моем исходном сообщении.

nomaam 27.01.2019 23:09

@nomaam Первое, что я вижу, это то, что вы используете исходную библиотеку, чтобы добраться до конечного значения (каждый раз присваивая ее себе). Таким образом вы потеряете оригинальный lib. В каждой итерации используйте временную переменную, для которой установлено значение lib, и повторяйте ее. (см. мой пример: var tempLib = lib;). Было бы очень полезно, если бы вы также могли опубликовать частичный пример вашего массива/объекта lib. Обратите внимание, что в моем примере я использовал объект, а не массив.

Z-Bone 28.01.2019 00:33

Я добавил короткий пример моего массива lib. Также я обновил свой скрипт, чтобы иметь tempLib, однако именно здесь я сталкиваюсь с неопределенными ошибками, как я упоминал в своих последних комментариях. Где вы на самом деле обновляете объект master lib с изменениями?

nomaam 28.01.2019 19:12

Привет @nomaam, пожалуйста, ознакомься с моим обновленным ответом. Он содержит фрагмент, показывающий полный рабочий цикл с предоставленным вами набором данных. Удачи :)

Z-Bone 28.01.2019 23:03

Обновление 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.info(lib[0][1][2][2]) // "sample3"

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

console.info(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);
  });
}

Спасибо вам за публикацию. Это похоже на идею @Z-Bone. Просто пытаюсь заставить его работать на моем конце. Смотрите мои последующие сообщения, прикрепленные к его решению.

nomaam 27.01.2019 22:04

Я пытаюсь протестировать ваше решение, но не могу использовать внешние библиотеки, такие как lodash.

nomaam 27.01.2019 22:52

Предполагая, что пути в libVars такие же, как и в lib, вы можете просто записать изменения в массив функций, которые вы повторно примените к своему объекту lib позже. :

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

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

const updates = [];

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

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

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

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

Спасибо, но я думаю, что это вызовет проблему, о которой я упоминал в вопросе, что меньший массив, содержащий изменения, будет в значительной степени иметь размер, аналогичный основному массиву, поскольку пустые значения массива все еще занимают память.

nomaam 27.01.2019 22:05

Единственное, что updates будет содержать, это функции, а не фактические данные, с которыми они работают.

customcommander 27.01.2019 22:22

Это можно решить с помощью эмуляции автовивификации с использованием прокси. Видеть:

https://en.wikipedia.org/wiki/Автовивификация

Автовивификация и Javascript

Другие вопросы по теме