如何使用 lodash 或不使用 lodash 通过特定值从嵌套 JSON 创建键数组?

How to create key array from nested JSON by particular value with lodash or without lodash?

我想创建值为“str”的键数组 我有以下嵌套 json:

[
  {
    "Attr": [
      {
        "power": { "p1": "str", "t3": "str" },
        "light": [
          {"test": "str"},
          {"test2": [ { "t4": "str" }]}
        ]
      }
    ]
  },
  {
    "Attr1": [
      {
        "power1": { "p2": "str", "t5": "str" },
        "light1": [
          { "test3": "str" },
          { "test_x": [
              { "t_x": "str" },
              { "t_y": [
                  { "t_y1": "str" }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

我想创建键值为“str”的键数组,

我想要得到以下数组输出:

["p1", "t3", "test", "p2", "t5", "test3", "t_x", "t_y1"]

如何根据特定值从嵌套 JSON 创建键数组?

尝试这样的事情:

var array = [];
function searchForStringInJsonRecursive (jsonData, str) {
    for(var i in jsonData) {
        // If the element is an Array or nested object continue to search
        if (typeof jsonData[i] === 'object') {
            searchForStringInJsonRecursive(jsonData[i], str);
        }
        // If the element is not an Object and matches str add the it to the array
        else if (jsonData[i] === str) {
            array.push(i);
        }
    }
}

假设您的 json 在一个名为 data 的变量中,您可以这样调用该函数: searchForStringInJsonRecursive(data, 'str');
array 将包含内容匹配 'str'

的所有键

如果你能写出一个性能最好的递归函数。

但是如果你想跳过递归调用(对于嵌套对象中的每个键),那么你可以尝试 JSON.parse 带有附加参数(回调),它将被它递归调用。作为通用解决方案,我添加了一个片段(JSON.parse,假设帮助编写递归函数不应该被接受/这个答案的一部分)。

但请记住,如果您担心性能效率,则不应使用它,因为您必须进行字符串化(可能是一个大对象)并再次解析。但是,如果你有一个 JSON 字符串,它应该是最好的解决方案之一。

var anyObject = [
  {
    "Attr": [
      {
        "power": { "p1": "str", "t3": "str" },
        "light": [
          {"test": "str"},
          {"test2": [ { "t4": "str" }]}
        ]
      }
    ]
  },
  {
    "Attr1": [
      {
        "power1": { "p2": "str", "t5": "str" },
        "light1": [
          { "test3": "str" },
          { "test_x": [
              { "t_x": "str" },
              { "t_y": [
                  { "t_y1": "str" }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

function getKeys(obj, str) {
let resultArr = [];
 JSON.parse(JSON.stringify(obj), (key, val) => {
  if(val === str) { resultArr.push(key) }
  return val;
 } )
return resultArr;
}

console.log(getKeys(anyObject, 'str'))

这不是特定情况,如果你在 JSON.parse 中传递另一个回调,你可以拥有所有的键,也可以使用它转换对象(返回转换后的值而不是实际值)

而如果你想使用lodash递归迭代对象,那么你可以使用 _.cloneDeepWith 用于递归迭代对象。

这是一个工作示例:

let anyObject = [
  {
    "Attr": [
      {
        "power": { "p1": "str", "t3": "str" },
        "light": [
          {"test": "str"},
          {"test2": [ { "t4": "str" }]}
        ]
      }
    ]
  },
  {
    "Attr1": [
      {
        "power1": { "p2": "str", "t5": "str" },
        "light1": [
          { "test3": "str" },
          { "test_x": [
              { "t_x": "str" },
              { "t_y": [
                  { "t_y1": "str" }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
];

function getKeys(obj, str) {
  let resultArr = [];
  _.cloneDeepWith(obj, (value, key) => { value === 'str' && resultArr.push(key)});
  return resultArr;
}

console.log(getKeys(anyObject, 'str'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

恕我直言,您可能正在寻找这样的东西:

var testArr = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];


var strFind = (arr, accumulator = []) => {
  arr.forEach(obj => {
    Object.entries(obj).forEach(([key, value]) => {
      if (value === "str") accumulator.push(key);
      if (Array.isArray(value)) strFind(value, accumulator);
      if (key.includes("power")) {
        Object.entries(value).forEach(([cKey, cValue]) => {
          if (cValue === "str") accumulator.push(cKey);
        })
      }
    });
  })
  return accumulator;
}

console.log(strFind(testArr));

另一个尝试使用 JSON.stringify 和字符串解析:

const result = JSON.stringify(data)
  .match(/"[^"]+":"str"/g) // get all "xxx":"str" pairs
  .map(r => r.substring(1, r.indexOf(':') - 1)); // pick out all "xxx"

console.log(result);
// ["p1", "t3", "test", "t4", "p2", "t5", "test3", "t_x", "t_y1"]

这是使用 lodash 的一种方法:

var testArr = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];

var findStr = function(o) {
  return _(o)
   .map(function(v, k) {
       return v === 'str'
           ? k
           : _.isObject(v) ? findStr(v) : null;
   })
   .compact()
        .flatten()
   .value();
};

console.log(findStr(testArr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

还有另一种可能性,利用 JSON.stringify 的自然递归性质:

const input = [{"Attr":[{"power":{"p1":"str","t3":"str"},"light":[{"test":"str"},{"test2":[{"t4":"str"}]}]}]},{"Attr1":[{"power1":{"p2":"str","t5":"str"},"light1":[{"test3":"str"},{"test_x":[{"t_x":"str"},{"t_y":[{"t_y1":"str"}]}]}]}]}];

const output = [];
JSON.stringify(input, (key, val) => {
  if (val === 'str') output.push(key);
  return val;
});
console.log(output);

我做过……我用过lodash。我的代码如下:

var arrayData = [];
var teatData = [
  {
    "Attr": [
      {
        "power": { "p1": "str", "t3": "str" },
        "light": [
          {"test": "str"},
          {"test2": [ { "t4": "str" }]}
        ]
      }
    ]
  },
  {
    "Attr1": [
      {
        "power1": { "p2": "str", "t5": "str" },
        "light1": [
          { "test3": "str" },
          { "test_x": [
              { "t_x": "str" },
              { "t_y": [
                  { "t_y1": "str" }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
];

function getKeyArray(data, arrayData) {
    if (Array.isArray(data)) {
      _.forEach(data, (obj, key) => {
        this.getKeyArray(obj, arrayData);
      });
    } else if (_.isPlainObject(data)) {
      _.forEach(data, (obj, key) => {   
        if (obj === "str") {
          arrayData.push(key);
        } else if (Array.isArray(obj) || _.isPlainObject(obj)) {
          this.getKeyArray(obj, arrayData);
        }
      });
    }
  }
  
  getKeyArray(teatData, arrayData);
  
  console.log(arrayData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>