在嵌套数组中通过匹配属性查找对象

39

我发现当我的条件涉及到嵌套数组时,找不到一种方法来find对象。

var modules = [{
    name: 'Module1',
    submodules: [{
        name: 'Submodule1',
        id: 1
      }, {
        name: 'Submodule2',
        id: 2
      }
    ]
  }, {
    name: 'Module2',
    submodules: [{
        name: 'Submodule1',
        id: 3
      }, {
        name: 'Submodule2',
        id: 4
      }
    ]
  }
];

这样做行不通,因为submodules是一个数组而不是对象。是否有任何简写方法可以使其工作?我试图避免手动迭代数组。

_.where(modules, {submodules:{id:3}});
6个回答

88
Lodash允许你像这样在嵌套数据(包括数组)中进行过滤: _.filter(modules, { submodules: [ { id: 2 } ]});

13
你也可以使用 _.find 完全相同的语法。 - Devon Sams
2
@DevonSams尽管_.filter返回过滤后的数组或空数组,而_.find则返回匹配的元素,它可以是对象、数组、数字、字符串、布尔值或未定义。 - user115014
12
有没有办法只返回嵌套对象,而不是整个父对象? - Anurag pareek
如何在一个颜色数组内包含一个尺码数组,在尺码数组内包含一个条形码数组,并针对该条形码数组定位对象?我该如何直接指向这些条形码? - Ibad Shaikh

28

这是我想出来的:

_.find(modules, _.flow(
    _.property('submodules'),
    _.partialRight(_.some, { id: 2 })
));
// → { name: 'Module1', ... }
使用 flow(),你可以构建一个回调函数来完成需要的操作。当调用时,数据会通过每个函数“流动”。你首先想要的是 submodules 属性,你可以使用 property() 函数来获取它。
然后将子模块数组传入 some(),如果它包含你要查找的子模块(在这里是 ID 2),则返回 true。
如果你要查找多个模块而不仅仅是第一个找到的模块,请将 find() 替换为 filter()

我喜欢它,谢谢!虽然不如动态路径优雅,但是lodash不支持。也许我会制作一个mixin... - helion3
2
FYI,在 Lodash 4.0 中,他们移除了 .any() 函数。现在你需要使用 .some()。 - Justin

1
我认为你最好的机会是使用一个函数来获取模块。
_.select(modules, function (module) {
  return _.any(module.submodules, function (submodule) {
    return _.where(submodule, {id:3});
  });
});

尝试使用以下代码获取子模块:

.where(.pluck(modules, "submodules"), {submodules:{id:3}});


请注意,此处保留了HTML标签。

好主意。我必须使用 _flatten,因为 _.pluck 返回一个数组的数组。 - helion3
(是的,flatten后来浮现在我的脑海中),但我完全改变了我的答案,因为它行不通。希望能够实现 :) - Mabedan
1
但它确实起作用了。使用flatten+pluck逻辑,我的测试可以工作。http://jsbin.com/howazulexe/1/edit?js - helion3
我认为目标是获取父模块,而不是子模块。在那种情况下,是的:D - Mabedan
哦,好想法。虽然不适用于我的情况,但这同样是一个有用的用例。如果您想更新您的答案并提供两种方法,我会标记它为已接受。我没有看到更简洁的方法。老实说,我很惊讶没有匹配器支持。 - helion3

1

我研究了一下,我认为最好的选择是使用Deepdash。它是一组方法,可以进行深度过滤、查找等操作。

当然,只使用lodash也是可能的,但使用Deepdash更容易。

我试图将先前的答案转换为最新的Lodash版本,但那并没有起作用。在Lodash v4中,每种方法都已被弃用。可能的替代品:select = map或filter,any = some,where = filter)

findDeep返回一个带有某些信息的对象,以便找到该项(仅包含一些值,请参阅docs获取更多详细信息):

  • value是找到的对象
  • key是嵌套数组中的索引
  • parent是该值的父级

因此,findDeep的代码如下:

const modules = [{
  name: 'Module1',
  submodules: [{
    name: 'Submodule1',
    id: 1
  }, {
    name: 'Submodule2',
    id: 2
  }]
}, {
  name: 'Module2',
  submodules: [{
    name: 'Submodule1',
    id: 3
  }, {
    name: 'Submodule2',
    id: 4
  }]
}];

const getModule = (modules, id) =>
  _.findDeep(modules, module => module.id === id, {
    childrenPath: "submodules"
  });


const resultEl = document.getElementById("result");
const foundModule = getModule(modules, 3).value;

resultEl.innerText = JSON.stringify(foundModule, null, 2);
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script>
  deepdash(_);
</script>

<h2>Example to get module with id = 3</h2>
<pre id="result"></pre>


0

另一种解决方案可以是:

const var = _.find(modules, (item) => {
        return (item.submodules.id === 2)
      })

你可��使用 _.find 获取第一个出现的值,或者使用 _.filter 获取所有符合条件的值。

0

如果您想通过关键字进行搜索:

const searchWord = 'Hello world'.trim().toLowerCase();
const result = JSON.stringify(object).trim().toLowerCase().includes(searchWord);
  1. 修剪并将搜索词转换为小写。
  2. 将对象字符串化,修剪并转换为小写。
  3. 检查是否包含搜索词。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接