【问题标题】:How to filter an array based on the grand child array's values?如何根据大子数组的值过滤数组?
【发布时间】:2020-01-23 09:17:30
【问题描述】:

我正在尝试根据大子数组的值过滤父数组,但我的过滤方法效果不佳,并且 UI 没有更新。

这是我的过滤功能。

filterIt($event) {
    this.filter.RegCategoryName = $event.target.value;
    this.dataObject = staticData.filter(value => 
        value.List.filter(ch => ch.RegistrationCategory.filter(gChild =>
            Object.keys(this.filter).every(ob => 
                String(gChild[ob]).toLowerCase().includes(String(this.filter[ob]).toLowerCase())
            )
        )).length
    )
}

Live Demo

预期:

当用户键入new Course 时,它应该只在程序列中显示DP Programme

【问题讨论】:

    标签: javascript angular ecmascript-6 angular8


    【解决方案1】:

    您可以通过结合使用mapfiltersome Array 方法来实现此目的。使用扩展运算符...,这样您的原始数组就不会在子对象中得到更新。

    filterIt($event) {
        this.filter.RegCategoryName = $event.target.value;
        this.dataObject = staticData.filter(value => {
            const data = { ...value };
            data.List = data.List.map(ch => {
                const list = { ...ch };
                list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
                    return gChild.RegCategoryName.toLowerCase().indexOf(this.filter.RegCategoryName.toLowerCase()) !== -1
                });
                return list;
            });
            return data.List.some(list => !!list.RegistrationCategory.length);
        });
    }
    

    注意:避免使用首字母大写的变量名。

    这是StackBlitz 上的一个工作示例。

    解释

    这里使用的结构相当复杂,所以我想我会从里到外开始。让我们从最里面的filter开始。

    list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
        return gChild.RegCategoryName.toLowerCase().indexOf(this.filter.RegCategoryName.toLowerCase()) !== -1
    });
    

    filter() 方法创建一个新数组,其中包含所有通过所提供函数实现的测试的元素。

    这个应该够清楚了。此处使用的条件与 Angular Material 的 mat-table 过滤器中使用的条件相同。如果RegCategoryName 包含搜索词,这将过滤。我说包含是因为即使您的搜索词是ew,它也会匹配new Course。如果这不是您想要的,您可以改用startsWith。仅当您的搜索词是 new 而不是 ew 时才会匹配。

    list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
        return gChild.RegCategoryName.toLowerCase().startsWith(this.filter.RegCategoryName.toLowerCase())
    });
    

    移动到第一个父数组List。我们不想filter 或更改此处的对象。相反,我们只想要相同的对象,但使用新过滤的RegistrationCategory。这非常适合map,因为map 返回一个具有相同数量对象的数组(如果需要,可以对对象中的元素进行一些修改)。

    map() 方法创建一个新数组,其结果是在调用数组中的每个元素上调用提供的函数。

    所以在我们的map 中,我们将使用我们在上面创建的filter 更新RegistrationCategory。我们不能直接修改ch,因为这会改变原始对象。因此,我们将使用spread syntax 浅克隆ch 到变量list,使用上面的filter 在我们的新list 变量中修改RegistrationCategory 并返回对象。现在,我们只需更新每个对象中的 RegistrationCategory,就可以得到 List 数组。

    现在是最后一块,我们需要通过staticData 发送filter。正如我们在map 中所做的那样,我们将在这里再次使用扩展语法,因为我们不想更新原始对象。 data.List 现在将通过我们最里面的过滤器过滤每个 RegistrationCategory,所以我们只需要根据 List 数组是否有任何 RegistrationCategory 长度更大的对象返回一个 true/false 值大于 0。我们可以使用some

    some() 方法测试数组中的至少一个元素是否通过了提供的函数实现的测试。它返回一个布尔值。

    因此,如果List 数组中的任何RegistrationCategory 的长度大于0(因为这就是我们关心的全部,在我们最里面的过滤器过滤List 之后是否仍然存在任何RegistrationCategory),它返回@ 987654375@ 并添加到过滤后的dataObject

    这样我们得到staticData 中的每个对象,其List 数组包含一个对象,其中RegistrationCategory 有一些数据。

    我希望这能说明您的代码出现问题的原因以及您不能对所有三个数组都使用过滤器的原因。

    【讨论】:

    • 我抛出了错误,你能在演示中更新吗? - 感谢advacne
    • 当然,我已将其添加到我的答案中
    • 效果很好。你真是个天才。但我不知道如何正确混合所有这些地图、过滤器和一些。我在哪里可以倾斜?背后的逻辑是什么?
    • 澄清一下,为什么我的功能不起作用?什么是拦截器?你能帮我理解吗?你能详细说明你的步骤吗? - 只想向和你一样的人学习和帮助他人!!
    • 向您致以最良好的祝愿。感谢您让我了解了复杂性。
    猜你喜欢
    • 2018-11-06
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 2015-10-13
    • 2017-03-13
    相关资源
    最近更新 更多