遍历javascript中的对象并以特定格式转换它

时间:2017-12-06 15:29:41

标签: javascript object

我有以下对象结构:

{
    a: {
        b: "abc",
        c: [
            {
                d: "pqr",
                e: true
            },
            {
                f: 1,
                e: ["xyz", 1]
            }
        ]
    }
}

现在我想以预期输出中显示的特定格式转换这些结构。

我试图遍历上面的结构,但构造的路径不正确 这就是我正在做的事情

const getFinalNode = function(data, path){
  if (typeof data === 'object'){
    for (let key in data) {
      // console.log(key);
      if (typeof data[key] === 'object'){
        path += key+'/'
        getFinalNode(data[key], path)
        // console.log(true);
      }else{
        console.log({
          value: data[key],
          key: key,
          path:path
        })
      }
    }
  }
}
getFinalNode(data, ""); 

我的预期输出应为

[
    {
        name: "b",
        value: "abc",
        path: "a/b"
    },
    {
        name: "d",
        value: "pqr",
        path: "a/c/0/d"
    },
    {
        name: "e",
        value: true,
        path: "a/c/0/e"
    },
    {
        name: "f",
        value: 1,
        path: "a/c/1/f"
    },
    {
        name: "e",
        value: 'xyz',
        path: "a/c/1/e"
    },
    {
        name: "e",
        value: 1,
        path: "a/c/1/e"
    }
]

那么我如何遍历上面的结构并将其转换为预期的输出,或者我可以在现有代码中使用任何解决方案。

现在我得到以下输出

enter image description here

5 个答案:

答案 0 :(得分:0)

您应该将path和累积的数组acc传递给getFinalNode的递归调用:

const getFinalNode = function(data, acc = [], path = "") {         // default values for acc and path, so we won't bother ourselves with that
    for(let key in data) {                                         // for each key in the object/array data
        if(data.hasOwnProperty(key)) {                             // if this is an own property
            if(data[key] && typeof(data[key]) === "object") {      // if the value of the current property is an object/array (not null: typeof null === "object")
                getFinalNode(data[key], acc, path + "/" + key);    // then traverse it, passing acc to add to what we already have
            } else {                                               // otherwise
                acc.push({                                         // make a leaf object and push it to the accumulator acc
                    path: path.slice(1) + "/" + key,               // slice to remove the first "/" from path
                    name: key,
                    value: data[key]
                });
            }
        }
    }
    return acc;
}


let data = {"a":{"b":"abc","c":[{"d":"pqr","e":true},{"f":1,"e":["xyz",1]}]}};

let result = getFinalNode(data);
console.log(result);

答案 1 :(得分:0)

你只需要通过一个阵列,然后对你正在建造的路径做一点调整。

在最终路径中包含最后一项有点令人惊讶,并进行了一些额外的调整,但我认为这是你在结果中寻找的内容。



const getFinalNode = function(data, path, result){
  result = result || [];

  // This check isn't needed if the initial call will always be an object.
  if (typeof data === 'object'){ 
    for (let [key, val] of Object.entries(data)) {
      if (typeof val === 'object'){
        getFinalNode(val, path ? (path + "/" + key) : key, result);

      }else{
        const notNum = isNaN(key);
        result.push({
          name: notNum ? key : path.slice(path.lastIndexOf("/") + 1),
          value: val,
          path:path + (notNum ? "/" + key : "")
        });
      }
    }
  }
  return result;
}

const data = {
    a: {
        b: "abc",
        c: [
            {
                d: "pqr",
                e: true
            },
            {
                f: 1,
                e: ["xyz", 1]
            }
        ]
    }
};

console.log(getFinalNode(data, ""));




我在Object.entries()中使用for-of进行了解构赋值,只是为了方便将键和值赋给变量。您原来的for-in循环也很好。

答案 2 :(得分:0)

有两件事你没有得到预期的输出:   - 当数据[“key”]不是对象时,您不添加路径   - 您正在寻找获得数组输出但是您要分开打印每个元素。

看着你想要的输出我看到路径总是包括b,即使b和c是兄弟姐妹,并且不允许它们都在同一个路径中。把这作为打字错误,我修改了一下脚本以获得正确的输出:

var data = {a: { b: "abc", c: [ { d: "pqr", e: true},{ f: 1, e: ["xyz", 1] }]}};

var output = [];

getFinalNode = function(data, path){
  if (typeof data === 'object'){
    for (let key in data) {
      // console.log(key);
        path.push(key)
        getFinalNode(data[key], path)

        // console.log(true);
        if (typeof data[key] != 'object'){ 
        output.push({
          value: data[key],
          key: key,
          path:path.join("/")
        });}      
    }
  }
  path.splice(-1,1) 
}

getFinalNode(data, []);

console.log(output);

答案 3 :(得分:0)

对于有趣,肮脏的解决方案,孩子们不会在家里这样做!

function getFinalNode(node) {
  return (function rec(obj, path='', results=[]) {
    path = path && (path + '/')
    return Object.entries(obj)
      .reduce((arr, [name, value]) => void (typeof value === 'object'
          ? rec(value, path + name, arr)
          : arr.push({ name, value, path: path + name })) || arr,
        results)
  })(node)
}

console.log(getFinalNode({a:{b:"abc",c:[{d:"pqr",e:true},{f:1,e:["xyz",1]}]}}))

解释一下:

path = path && (path + '/')

如果path为空,则将评估条件的第一部分,因此将得到一个空字符串。否则,将评估第二部分,并进行连接。

void (whatEverExpression) || arr

void将使whatEverExpression返回未定义,因此将返回arr

(这是一个技巧,在减少某些东西时我觉得很少。即使ESLint禁止使用void:D)

编辑:受摇滚明星答案的启发,entries,甚至更好:D

答案 4 :(得分:0)

您可以使用函数来收集项目,并使用函数进行递归调用以迭代对象。

function traverse(object) {

    function iter(o, p) {
        Object.keys(o).forEach(function (k) {
            if (o[k] && typeof o[k] === 'object') {
                return iter(o[k], p.concat(k));
            }
            result.push({ name: k, value: o[k], path: p.join('/') });
        });
    }

    var result = [];
    iter(object, []);
    return result;
}

var object = { a: { b: "abc", c: [{ d: "pqr", e: true }, { f: 1, e: ["xyz", 1] }] } };

console.log(traverse(object));
.as-console-wrapper { max-height: 100% !important; top: 0; }