简体   繁体   English

使用 JavaScript 中的递归更新嵌套的 json object

[英]update nested json object using recursion in JavaScript

I'm trying to create an updated object from an existing object.我正在尝试从现有的 object 创建更新的 object。 The sample object is:样品 object 是:

// sample object
const testObj = {
  a: 1,
  b: {
    c: 2,
    d: {
      e: 3,
      f: {
        g: 4
      }
    }
  }
};

I want to create a new object from the above object with some concatenation of each value:我想从上面的 object 中创建一个新的 object ,每个值都有一些串联:

// expected object
const expectedObject= {
  a: '1 a',
  b: {
    c: '2 a',
    d: {
      e: '3 a',
      f: {
        g: '4 a'
      }
    }
  }
};

here is my sample code:这是我的示例代码:

let expectedObject = {};
const newObject = object => {
  Object.entries(object).forEach(([key, value]) => {
    if (typeof value === "object") {
      Object.keys(value).map(key => {
        value[key] = value[key] + " a";
        return value;
      });

      expectedObject[key] = value;
      //return newTest;
    } else {
      expectedObject[key] = value;
      return expectedObject;
    }
  });
  return expectedObject;
};
console.log(newObject(testObj));

the outcome in console is:控制台中的结果是:

{a: 1, b: {…}}
a: 1
b:
c: "2 a"
d: "[object Object] a"
__proto__: Object
__proto__: Object

I wanted to use recursion here and also tried it but no luck.我想在这里使用递归并且也尝试过但没有运气。 any help, thanks?任何帮助,谢谢?

You could get a new object my mapping changed values and creating new objects.您可以获得一个新的 object 我的映射更改了值并创建了新对象。

 function map(object, fn) { return Object.fromEntries(Object.entries(object).map(([k, v]) => [k, v && typeof v === 'object'? map(v, fn): fn(v)]) ); } var object = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } }, result = map(object, v => v + ' a'); console.log(result);

If you have arrays inside, you could add a check in advance and map the values.如果您有 arrays 内部,您可以提前添加检查和 map 值。

 const map = fn => { const iter = v => v && typeof v === 'object'? Array.isArray(v)? v.map(iter): Object.fromEntries(Object.entries(v).map(([k, v]) => [k, iter(v, fn)])): fn(v); return iter; }; var object = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4, k: [5, 6] } } } }, addA = map(v => v + ' a'), result = addA(object); console.log(result);

This is simply a refactoring of the answer from @user633183.这只是对@user633183 答案的重构。 I like that approach a lot, but think it can be simplified by extracting two more reusable functions.我非常喜欢这种方法,但认为可以通过提取两个可重用的函数来简化它。 This started as a comment on that answer, but I thought it would be better to be explicit.这开始是对该答案的评论,但我认为最好是明确的。

 const map = (f) => (a) => a.map(f) const mapObj = (f) => (o) => Object.entries (o).reduce ( (a, [k, v] ) => ({...a, [k]: f(v) }), {}) const traverse = (f) => (t) => Array.isArray(t)? map (traverse (f)) (t): Object(t) === t? mapObj (traverse (f)) (t): f (t) const input = { a: [ 1, 11, 111 ], b: { c: 2, d: { e: [ 3, { f: { g: 4 } } ] } } } const output = traverse(x => `${x} a`) (input) console.log(output)

mapObj can be written in many different ways. mapObj可以用许多不同的方式编写。 Here are two alternatives:这里有两种选择:

const mapObj = (f = identity) => (o = {}) => 
  Object .fromEntries (Object .entries (o) .map (([ k, v ]) => [ k, f (v) ]))


const mapObj = (f = identity) => (o = {}) => 
  Object .assign .apply (null, Object .entries (o) .map (([ k, v ]) => ({ [k]: f (v) 

Here's an approach using a modification of the original code to demonstrate what needed to be changed in order to make it work.这是一种使用修改原始代码的方法来演示需要更改哪些内容才能使其正常工作。 You had some things switched up reading the value and setting the new one.你有一些东西被切换到读取value并设置新值。 Also I'm using the spread operator to clone the object before modifying it.此外,我正在使用扩展运算符在修改 object 之前对其进行克隆。

 const testObj = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } }; const newObject = object => { const clonedObj = {...object }; const entries = Object.entries(clonedObj); entries.forEach(([key, value]) => { if (typeof value === "object") { clonedObj[key] = newObject(value); } else { clonedObj[key] = value + " a"; } }); return clonedObj; }; console.log(newObject(testObj)); console.log(testObj); // prove that the original object hasn't changed

Here's a simple recursive technique.这是一个简单的递归技术。 It is similar to Nina's but it preserves arrays, if present in the structure.它类似于 Nina 的,但它保留了 arrays(如果存在于结构中)。

  1. If the input, t , is an array, create a new array by traversing each array value, v , with the traversing function, f如果输入t是一个数组,则通过遍历每个数组值v创建一个新数组,其中遍历 function, f
  2. (inductive) Otherwise t is not an array. (归纳)否则t不是数组。 If t is an object, create a new object from key value pairs, [ k, v ] , by traversing each value, v , with the traversing function, f如果t是 object,则从键值对[ k, v ]创建一个新的 object,通过遍历每个值v ,遍历f
  3. (inductive) Otherwise t is not an array and t is not an object. (归纳)否则t不是数组,并且t不是object。 This means t is either a primitive value, such as string, number, or null这意味着t是原始值,例如字符串、数字或null

Numbered comments below correspond to the explanation above -下面的编号注释对应于上面的解释 -

 const identity = x => x const traverse = (f = identity, t = {}) => Array.isArray(t) // 1? Array.from(t, v => traverse(f, v)): Object(t) === t // 2? Object.fromEntries(Object.entries(t).map(([ k, v ]) => [ k, traverse(f, v) ])): f (t) // 3 const input = { a: [ 1, 11, 111 ], b: { c: 2, d: { e: [ 3, { f: { g: 4 } } ] } } } const output = traverse(x => `${x} a`, input) console.log(output)

Here is a solution using object-scan .这是使用object-scan的解决方案。 It works by building the solution at the same time as the input is traversed.它通过在遍历输入的同时构建解决方案来工作。

 // const objectScan = require('object-scan'); const testObj = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } }; const cloneAndModify = (obj) => objectScan(['**'], { breakFn: ({ property, value, isLeaf, context }) => { if (property === undefined) { return; } const ref = context[context.length - 1]; if (?(property in ref)) { ref[property] = isLeaf: `${value} a`; {}. } context;push(ref[property]), }: filterFn. ({ context }) => { context;pop(), } })(obj; [{}])[0]; const r = cloneAndModify(testObj). console;log(r): // => { b: { d: { f: { g, '4 a' }: e, '3 a' }: c, '2 a' }: a: '1 a' }
 .as-console-wrapper {max-height: 100%;important: top: 0}
 <script src="https://bundle.run/object-scan@13.7.1"></script>

Disclaimer : I'm the author of object-scan免责声明:我是对象扫描的作者

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM