Je travaille en Javascript et je crée une application hors ligne.
J'ai un très grand tableau, plus de 10 Mo. Je dois enregistrer des éléments du tableau où un utilisateur a effectué une modification, mais l'écriture / la lecture du tableau sur le disque est trop lente.
Je voudrais créer un deuxième tableau qui contient uniquement les modifications apportées par l'utilisateur, afin que je puisse enregistrer ce plus petit tableau et ensuite, lorsque j'ai besoin de charger des modifications, il peut refléter ses modifications dans le grand tableau.
Par exemple:
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];
}
});
});
libVars contiendrait simplement les changements d'élément dans lib et n'aurait pas la même taille que le grand tableau lib comme l'utilisateur le fera n'interagit qu'avec une petite partie du grand tableau.
De toute évidence, cela ne fonctionne pas, car libVars n'a pas la même structure que lib, et si c'était le cas, cela prendrait également beaucoup de mémoire (Je pense que oui de toute façon!)
Je voudrais ensuite parcourir libVars et mettre à jour lib aux mêmes points d'élément où les modifications ont été enregistrées dans libVars.
Existe-t-il un moyen de sauvegarder un type de pointeur vers un emplacement dans lib que je pourrais stocker dans libVars avec la valeur d'élément associée?
Toute aide serait très appréciée.
Merci.
=======================
Exemple de mon grand tableau
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"] ...
4 Réponses :
Mise à jour du 28/01/2019 Basé sur les données de test de nomaam
@nomaam Veuillez vérifier l'extrait suivant. Je l'ai fait changer un chemin arbitraire dans le tableau lib . Le chemin que j'ai choisi est le suivant: lib [0] [1] [3] [4] .
Vous pouvez voir comment il renvoie initialement la valeur "non" puis après exécution de la solution de suivi des modifications, il renvoie la valeur "yes" .
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"}}}}
Réponse originale
Si je comprends bien votre défi, vous pouvez techniquement tenir un objet avec le chemin de la propriété que vous souhaitez modifier comme la clé et la valeur modifiée comme valeur.
disons que votre objet d'origine ressemble à ceci:
var libVars = {};
libVars['a.b.c.d'] = "no";
Vous pouvez garder un journal des changements dans un objet de sauvegarde (par exemple, les changements de valeur de "oui" à «non»).
Cela pourrait ressembler à ceci, avec . marquant une propriété imbriquée.
var lib = {a: {b: { c: { d: "yes"}}}}
Ensuite, lorsque vous souhaitez mettre à jour le grand tableau / objet d'origine de valeurs, vous pouvez faire ceci:
// 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])
Cela ne suppose-t-il pas qu'une clé ne peut pas avoir un . dans son nom? par exemple. {'a.b': {'c.d': 'yes'}}
@customcommander Ceci est un exemple d'approche possible. Vous pouvez remplacer le point de représentation d'imbrication par n'importe quel autre caractère. Vous pouvez également l'échapper, puis vous séparer avec l'opérateur d'échappement.
J'essaie de faire fonctionner votre exemple. J'obtiens des erreurs non définies sur la section tempLib = tempLib [pathPart]. J'aime le concept. Pouvez-vous s'il vous plaît clarifier pour moi, si j'accède normalement à un tableau comme lib [0] [1] [3] [6], y a-t-il un moyen de convertir une chaîne, sans boucle, comme lib ["0,1,3, 6 "], si possible, alors les chemins de chaîne directs" pointeurs "pourraient simplement être insérés et je n'aurais pas à me soucier des erreurs non définies ou des problèmes d'indexation dans la boucle.
J'ai publié ma tentative de votre solution avec des commentaires dans mon message d'origine
@nomaam La première chose que je vois, c'est que vous utilisez la bibliothèque d'origine pour vous rendre à la valeur finale (en l'attribuant à elle-même à chaque fois). De cette façon, vous perdez la lib d'origine. Dans chaque itération, utilisez une variable temporaire définie sur lib et effectuez une itération dessus. (voir mon exemple: var tempLib = lib; ). Ce serait très utile si vous pouviez également publier un exemple partiel de votre tableau / objet lib . Notez que dans mon exemple, j'ai utilisé un objet et non un tableau.
J'ai ajouté un court exemple de mon tableau lib. J'ai également mis à jour mon script pour avoir le tempLib, mais c'est là que je rencontre des erreurs non définies comme je l'ai mentionné dans mes derniers commentaires. Où mettez-vous réellement à jour l'objet de la bibliothèque principale avec les modifications?
Salut @nomaam, veuillez consulter ma réponse mise à jour. Il contient un extrait de code qui montre un cycle de travail complet avec l'ensemble de données que vous avez fourni. Bonne chance :)
Mise à jour 2
J'ai mis à jour ma réponse, pour me débarrasser de lodash , et elle semblait être égale à Z-Bone ' réponse de s. Sa variante est encore plus claire que la mienne.
Mise à jour le 28.01.2019
import { set } from 'lodash';
function patch(arr, edits) {
Object.keys(edits).forEach(key => {
const newValue = edits[key];
set(arr, key, newValue);
});
}
Réponse originale:
Une solution possible serait d'avoir un objet où vous suivez toutes les modifications.
const edits = {}; Et lorsque vous mettez à jour votre objet avec lib [x] [1] [y] [6] = "no"; vous enregistrez également votre modification :
edits[`${x}.1.${y}.6`] = "no";
En gros, vous créez simplement une chaîne contenant le chemin du changement.
Après avoir chargé votre objet de modification à partir du fichier, vous pouvez appliquer toutes les modifications au tableau d'origine avec le code suivant:
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;
}
Merci de votre publication. C'est similaire à l'idée de @ Z-Bone. J'essaye juste de le faire fonctionner de mon côté. Voir mes posts de suivi attachés à sa solution.
J'essaie de tester votre solution mais je ne peux pas utiliser de bibliothèques externes telles que lodash.
En supposant que les chemins dans libVars sont les mêmes dans lib , vous pouvez simplement enregistrer les modifications dans un tableau de fonctions que vous réappliquez sur votre lib objet ultérieurement: 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);
Merci, mais je pense que cela soulèverait le problème que j'ai mentionné dans la question, à savoir que le plus petit tableau contenant les modifications aura à peu près la même taille que le tableau principal, car les valeurs de tableau vides occupent toujours de la mémoire
La seule chose que les mises à jour contiendront sont les fonctions et non les données réelles sur lesquelles elles opèrent.
Cela peut être géré avec une autovivification émulée à l'aide de Proxy. Voir:
npmjs.com/package/json-pointer
@JoeWarner Merci mais je voudrais éviter toutes les bibliothèques.