J'ai un tableau et un exemple d'objet comme celui-ci:
const array = ['a', 'b.c', 'c.d.e']
const sample = {
'aa': test,
'a': 'value',
'b': {
'c': 'value'
},
'c': {
'd': {
'e': 'value'
}
},
'e': {
'f': {
'g': {
'h' : 'value'
}
}
}
}
const newSample = {}
const transformer = (array) => {
array.forEach(item => {
const itemArr = item.split('.')
if (itemArr.length === 1) {
console.log(sample[itemArr[0]])
newSample[itemArr[0]] = sample[itemArr[0]] + 1
}
// the condition goes on...
})
}
transformer(array)
console.log(newSample)Exemple
const newSample = {
'aa': 'test',
'a': 'oldvalue' + 1,
'b': {
'c': 'oldvalue' + 1
},
'c': {
'd': {
'e': 'oldvalue' + 1
}
},
'e': {
'f': {
'g': {
'h' : 'oldvalue'
}
}
}
}
Ensuite, je veux créer un nouvel objet basant sur l'échantillon. Le résultat devrait ressembler à ceci:
const sample = {
'aa': 'test',
'a': 'value',
'b': {
'c': 'value'
},
'c': {
'd': {
'e': 'value'
}
},
'e': {
'f': {
'g': {
'h' : 'value'
}
}
}
}
Je pense à une boucle dans le tableau et à compter la longueur de chaque élément. Cependant, ce n'est pas aussi efficace que le niveau du tableau et l'augmentation de l'échantillon. Y a-t-il des algorithmes qui peuvent être améliorés?
const array = ['a', 'b.c', 'c.d.e']
Merci ,
3 Réponses :
Il semble que vous vouliez simplement appliquer une nouvelle valeur à un ensemble de champs de portée.
Vous pouvez simplement boucler sur vos champs de portée souhaités et leur définir une nouvelle valeur. La réponse à la question suivante: Convertir la chaîne JavaScript en point la notation dans une référence d'objet fonctionne très bien pour cet ensemble de problèmes.
Si vous avez besoin de copier en profondeur ou de cloner l'objet, vous pouvez le sérialiser-désérialiser :
.as-console-wrapper { top: 0; max-height: 100% !important; }L'attribution normale PAS ne gère les copies complètes:
const array = ['a', 'b.c', 'c.d.e', 'e.f.g.h'];
const sample = {
'a': 'value',
'b': {
'c': 'value'
},
'c': {
'd': {
'e': 'value'
}
},
'e': {
'f': {
'g': {
'h': 'value'
}
}
}
};
const newSample = setValueForKeys(cloneObject(sample), array, 'someValue');
console.log('Updated:', newSample);
console.log('Original:', sample);
function setValueForKeys(source, keys, value) {
keys.forEach((key) => index(source, key, value));
return source;
}
function cloneObject(obj) {
return JSON.parse(JSON.stringify(obj));
}
// See: https://stackoverflow.com/a/6394168/1762224
function index(obj, is, value) {
if (typeof is == 'string') return index(obj, is.split('.'), value);
else if (is.length == 1 && value !== undefined) return obj[is[0]] = value;
else if (is.length == 0) return obj;
else return index(obj[is[0]], is.slice(1), value);
}
function multiIndex(obj, is) {
return is.length ? multiIndex(obj[is[0]], is.slice(1)) : obj;
}
function pathIndex(obj, is) {
return multiIndex(obj, is.split('.'))
}p >
function cloneObject(obj) {
return Object.assign({}, obj);
}
function cloneObject(obj) {
return JSON.parse(JSON.stringify(obj));
}
Cette solution est vraiment bonne. Cependant, il mute également l'objet d'origine :(
@DaleNguyen Ajout du clonage et des notes.
Vous pouvez le faire avec la boucle forEach pour boucler chaque élément du tableau, puis diviser chaque chemin vers le tableau, puis utiliser la méthode réduire sur ce tableau de chemins pour mettre à jour chaque propriété imbriquée.
const array = ['a', 'b.c', 'c.d.e']
const sample = {"a":"value","b":{"c":"value"},"c":{"d":{"e":"value"}},"e":{"f":{"g":{"h":"value"}}}}
function update(array, sample) {
array.forEach(c => {
c.split('.').reduce((r, e, i, a) => {
if (!a[i + 1]) r[e] = r[e] + 1
else return r[e] || {}
}, sample)
})
}
update(array, sample);
console.log(sample)
Cette solution est vraiment bonne. Cependant, il mute également l'objet d'origine :(
Vous pouvez réduire le nombre de clés fractionnées et enregistrer la dernière clé de l'affectation avec la dernière clé.
.as-console-wrapper { max-height: 100% !important; top: 0; }
function transformer(object, keys) {
return Object.entries(object).reduce((r, [k, v]) => {
r[k] = v && typeof v === 'object'
? transformer(v, keys.filter(s => s.startsWith(k + '.')).map(s => s.split('.').slice(1).join('.')))
: keys.includes(k) ? (v || '') + 1: v;
return r;
}, {});
}
const
keys = ['a', 'b.c', 'c.d.e']
object = { a: 'value', b: { c: 'value' }, c: { d: { e: 'value' } }, e: { f: { g: { h : 'value' } } } };
console.log(transformer(object, keys));
Approche non mutante en renvoyant une copie complète avec une valeur modifiée.
.as-console-wrapper { max-height: 100% !important; top: 0; }
const
keys = ['a', 'b.c', 'c.d.e']
object = { a: 'value', b: { c: 'value' }, c: { d: { e: 'value' } }, e: { f: { g: { h : 'value' } } } },
transformer = (objec, keys) => keys.reduce((r, s) => {
var path = s.split('.'),
last = path.pop(),
final = path.reduce((o, k) => o[k] = o[k] || {}, r);
final[last] = (final[last] || '') + 1; // or whatever you need change
return r;
}, object);
console.log(transformer(object, keys));
Cette solution est vraiment bonne. Cependant, il mute également l'objet d'origine :(
La seule différence que je peux voir entre votre
échantillonet le résultat souhaité est que certainesvaleursont changé ensomeValuemais on ne sait pas d'où cela vient . La structure a la même apparence - ce que vous demandez n'est vraiment pas clair.pourquoi
an'est-il pas imbriqué? etc?D'où vient la
value / someValue?Pardon. La question est mise à jour. La nouvelle valeur est calculée à partir de l'ancienne valeur.
voulez-vous un nouvel objet ou muter l'ancien?
@NinaScholz Je veux un nouveau. Les réponses ci-dessous semblent bonnes. J'ai besoin de temps pour vérifier les deux à moins que vous n'ayez une meilleure solution: D