javascript在嵌套数组中查找子对象

时间:2014-03-12 06:16:41

标签: javascript arrays

我有一个像下面这样的javascript结构(嵌套的对象数组)

var categoryGroups = [
    {
        Id: 1, Categories: [
            { Id: 1 },
            { Id: 2 }, 
        ]

    },
    {
        Id: 2, Categories: [
            { Id: 100 },
            { Id: 200 },
        ]

    }
]

我想找到一个匹配Id的子类别对象,假设类别ID都是唯一的。

我在下面有这个,但是想知道是否有更简洁的方法:

var category, categoryGroup, found = false;
for (i = 0; i < categoryGroups.length ; i++) {
    categoryGroup = categoryGroups[i];
    for (j = 0; j < categoryGroup.Categories.length; j++) {
        category = categoryGroup.Categories[j];
        if (category.Id === id) {
            found = true;
            break;
        }
    }
    if (found) break;
}

10 个答案:

答案 0 :(得分:8)

警告:这会使用仅在ECMAScript 5中添加的几个Array.prototype函数,因此除非您将其填充,否则无法使用旧版浏览器。

您可以遍历数组中的所有第一级对象,然后根据条件过滤类别并收集数组中的所有匹配项。您的最终结果将是匹配数组中的第一个元素(如果数组为空,则找不到匹配项)。

var matches = [];
var needle = 100; // what to look for

arr.forEach(function(e) {
    matches = matches.concat(e.Categories.filter(function(c) {
        return (c.Id === needle);
    }));
});

console.log(matches[0] || "Not found");

JSFiddle: http://jsfiddle.net/b7ktf/1/

参考

Array.prototype.forEach
Array.prototype.concat
Array.prototype.filter

答案 1 :(得分:5)

在ES2019中使用flatMap

const category = categoryGroups.flatMap(cg => cg.Categories).find(c => c.Id === categoryId);

答案 2 :(得分:1)

检查fiddle

中的代码
var categoryGroups = [
    {
        Id: 1, Categories: [
            { Id: 1 },
            { Id: 2 }, 
        ]

    },
    {
        Id: 2, Categories: [
            { Id: 100 },
            { Id: 200 },
        ]

    }
]
var id = 100;
var x = 'not found';
var category, categoryGroup, found = false;
for (i = 0; i < categoryGroups.length ; i++) {
    categoryGroup = categoryGroups[i];
    for (j = 0; j < categoryGroup.Categories.length; j++) {
        category = categoryGroup.Categories[j];
        if (category.Id == id) {
            var x = category.Id;
            found = true;
            break;
        }
    }
    if (found) break;
}
alert(x);

上面的代码检查是否在数组中找到了id = 100。如果发现将警告值,否则警报未找到。价值&#39; 100&#39;为了演示而被硬编码

答案 3 :(得分:1)

你可以将它包装在一个函数中以摆脱笨拙的break;语法,你可以将每个元素加载到for(;;)构造内的一个变量中,以减少几行。

function subCategoryExists(groups, id)
{
  for (var i = 0, group; group = groups[i]; ++i) {
    for (var k = 0, category; category = group.Categories[k]; ++k) {
      if (category.Id == id) {
        return true;
      }
    }
  }
  return false;
}

var found = subCategoryExists(categoryGroups, 100);

答案 4 :(得分:1)

使用NodeJS的lodash库(假设您正在使用NodeJS)的简单方法:

const _ = require('lodash');
let category ;
let categoryGroup = _.find(categoryGroups, (element)=>{
  category = _.find(element.Categories, {Id : 100});
  return category;
});

console.log(categoryGroup); // The category group which has the sub category you are looking for
console.log(category); // The exact category you are looking for

答案 5 :(得分:1)

使用reduce和递归:

function nestedSearch(value) {
    return categoryGroups.reduce(function f(acc, val) {
        return (val.Id === value) ? val :
            (val.Categories && val.Categories.length) ? val.Categories.reduce(f, acc) : acc;
    });
}

> try on JSFiddle

答案 6 :(得分:1)

仅使用Array.prototype.filter()

如果您确定要查找的ID存在,则可以执行以下操作:

var id = 200; // surely it exists
var category = arr.filter(g => g.Categories.filter(c => c.Id === id)[0])[0].Categories.filter(c => c.Id === id)[0];

如果不确定它是否存在:

var id = 201; // maybe it doesn't exist
var categoryGroup = arr.filter(e => e.Categories.filter(c => c.Id === id)[0])[0]; 
var category = categoryGroup ? categoryGroup.Categories.filter(c => c.Id === id)[0] : null;

jsfiddle

答案 7 :(得分:0)

您可以使用underscore

var cat = _(categoryGroups).
  chain().
  pluck('Categories').
  flatten().
  findWhere({Id: 2}).
  value();

我在这里做的是,我在一个数组中提取所有Categories值,然后重新选择正确的类别。

编辑:抱歉,第一次没有问你的问题。正如评论所暗示的那样,你可能不想仅仅使用下划线,但这就是我将如何做到的:)

答案 8 :(得分:0)

如果您想实际返回内部类别(而不只是检查其是否存在),可以使用reduce

return categoryGroups.reduce((prev, curr) => {
    //for each group: if we already found the category, we return that. otherwise we try to find it within this group
    return prev || curr.Categories.find(category => category.Id === id);
}, undefined);

这会短路内部类别,并触摸每个类别组一次。也可以将其修改为categoryGroups上的短路标志。

Here's a JS Fiddle demonstration.

答案 9 :(得分:0)

我们现在使用object-scan进行数据处理。一旦将头缠绕在它上,它就会非常强大。对于您的问题,它看起来像这样:

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

const lookup = (id, data) => objectScan(['Categories.Id'], {
  useArraySelector: false,
  abort: true,
  rtn: 'parent',
  filterFn: ({ value }) => value === id
})(data);

const categoryGroups = [{
  Id: 1,
  Categories: [{ Id: 1 }, { Id: 2 }]
}, {
  Id: 2,
  Categories: [{ Id: 100 }, { Id: 200 }]
}];

console.log(lookup(1, categoryGroups));
// => { Id: 1 }
console.log(lookup(100, categoryGroups));
// => { Id: 100 }
console.log(lookup(999, categoryGroups));
// => undefined