在 ES6 深度嵌套的对象的 javascript 数组中查找值

Posted

技术标签:

【中文标题】在 ES6 深度嵌套的对象的 javascript 数组中查找值【英文标题】:Find value in javascript array of objects deeply nested with ES6 【发布时间】:2018-03-01 22:45:07 【问题描述】:

在一个对象数组中,我需要找到一个 value -- 其中 keyactivity :但是 activity key 可以像这样深入嵌套在数组中:

const activityItems = [
    
        name: 'Sunday',
        items: [
            
                name: 'Gym',
                activity: 'weights',
            ,
        ],
    ,
    
        name: 'Monday',
        items: [
            
                name: 'Track',
                activity: 'race',
            ,
            
                name: 'Work',
                activity: 'meeting',
            ,
            
                name: 'Swim',
                items: [
                    
                        name: 'Beach',
                        activity: 'scuba diving',
                    ,
                    
                        name: 'Pool',
                        activity: 'back stroke',
                    ,
                ],
            ,
        ],    
    ,
     ...
     ...
];

所以我写了一个递归算法来找出某个活动是否在数组中:

let match = false;
const findMatchRecursion = (activity, activityItems) => 
    for (let i = 0; i < activityItems.length; i += 1) 
        if (activityItems[i].activity === activity) 
            match = true;
            break;
        

        if (activityItems[i].items) 
            findMatchRecursion(activity, activityItems[i].items);
        
    

    return match;
;

是否有ES6 方法来确定活动是否存在于这样的数组中?

我尝试过这样的事情:

const findMatch(activity, activityItems) 
    let obj = activityItems.find(o => o.items.activity === activity);
    return obj;

但这不适用于深度嵌套的活动。

谢谢

【问题讨论】:

【参考方案1】:

您可以使用some() 方法和递归来查找活动是否存在于任何级别并返回真/假作为结果。

const activityItems = ["name":"Sunday","items":["name":"Gym","activity":"weights"],"name":"Monday","items":["name":"Track","activity":"race","name":"Work","activity":"meeting","name":"Swim","items":["name":"Beach","activity":"scuba diving","name":"Pool","activity":"back stroke"]]]

let findDeep = function(data, activity) 
  return data.some(function(e) 
    if(e.activity == activity) return true;
    else if(e.items) return findDeep(e.items, activity)
  )


console.log(findDeep(activityItems, 'scuba diving'))

【讨论】:

【参考方案2】:

首先,一旦通过递归调用找到匹配项,就可以通过暂停来改进您的功能。此外,您既要在外面声明match,也要返回它。可能会更好地返回。

const findMatchRecursion = (activity, activityItems) => 
    for (let i = 0; i < activityItems.length; i += 1) 
        if (activityItems[i].activity === activity) 
            return true;
        

        if (activityItems[i].items && findMatchRecursion(activity, activityItems[i].items) 
            return true;
        
    

    return false;
;

没有内置的深度搜索,但如果您愿意,可以将 .find 与命名函数一起使用。

var result = !!activityItems.find(function fn(item) 
  return item.activity === "Gym" || (item.items && item.items.find(fn));
);

【讨论】:

除非我遗漏了什么,否则这将返回包含搜索对象的最顶层父级,而不是对象本身。【参考方案3】:

虽然不如递归算法优雅,但您可以 JSON.stringify() 数组,它给出了:

["name":"Sunday","items":["name":"Gym","activity":"weights"],"name":"Monday","items":["name":"Track","activity":"race","name":"Work","activity":"meeting","name":"Swim","items":["name":"Beach","activity":"scuba diving","name":"Pool","activity":"back stroke"]]]

然后您可以使用template literal 来搜索模式:

`"activity":"$activity"`

功能齐全:

findMatch = (activity, activityItems) =>
  JSON.stringify(activityItems).includes(`"activity":"$activity"`);

const activityItems = [
    name: 'Sunday',
    items: [
      name: 'Gym',
      activity: 'weights',
    , ],
  ,
  
    name: 'Monday',
    items: [
        name: 'Track',
        activity: 'race',
      ,
      
        name: 'Work',
        activity: 'meeting',
      ,
      
        name: 'Swim',
        items: [
            name: 'Beach',
            activity: 'scuba diving',
          ,
          
            name: 'Pool',
            activity: 'back stroke',
          ,
        ],
      ,
    ],
  
];

findMatch = (activity, activityItems) =>
  JSON.stringify(activityItems).includes(`"activity":"$activity"`);

console.log(findMatch('scuba diving', activityItems)); //true
console.log(findMatch('dumpster diving', activityItems)); //false

【讨论】:

【参考方案4】:

我们现在使用object-scan 来处理像这样的简单数据处理任务。一旦您了解如何使用它,它真的很棒。以下是如何回答您的问题

// const objectScan = require('object-scan');

const find = (activity, input) => objectScan(['**'], 
  abort: true,
  rtn: 'value',
  filterFn: ( value ) => value.activity === activity
)(input);

const activityItems = ["name":"Sunday","items":["name":"Gym","activity":"weights"],"name":"Monday","items":["name":"Track","activity":"race","name":"Work","activity":"meeting","name":"Swim","items":["name":"Beach","activity":"scuba diving","name":"Pool","activity":"back stroke"]]]

console.log(find('scuba diving', activityItems));
// =>  name: 'Beach', activity: 'scuba diving' 
.as-console-wrapper max-height: 100% !important; top: 0
&lt;script src="https://bundle.run/object-scan@13.8.0"&gt;&lt;/script&gt;

免责声明:我是object-scan的作者

【讨论】:

以上是关于在 ES6 深度嵌套的对象的 javascript 数组中查找值的主要内容,如果未能解决你的问题,请参考以下文章

使用 Javascript 根据深度值过滤嵌套对象

检查 JavaScript 中是不是存在深度嵌套对象属性的最简单方法是啥? [复制]

Ramda js:具有嵌套对象数组的深度嵌套对象的镜头

javascript 数组对象与嵌套循环写法

测试嵌套 JavaScript 对象键是不是存在

测试嵌套 JavaScript 对象键是不是存在