一尘不染

从JSON数组中删除重复的对象

javascript

我有一个看起来像这样的数组:

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

而且我需要删除重复项,以便保留类似以下内容:

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

我尝试安装underscore.js并使用._uniq,但这似乎仅key:value在对象中出现一对时才起作用。我似乎无法使它跨多个键工作。

当我尝试类似的东西:

var uniqueStandards = _.uniq(standardsList, function(item, key, Domain){
    return item.Domain;
});

我只得到前三个唯一值(每个年级一个)。但是我需要所有年级和领域的唯一值。是否有一种简单的方法将两个键都馈给_.uniq函数?

最终,我需要一个列表,其中每个唯一的等级作为标题,唯一的域作为列表项,以传递到HTML页面中。我可能会犯错,因此,如果有更简单的方法来实现最终目标,则可以公开征求意见。

提前致谢!

编辑: 得到一些好的回应,并想澄清我的最终目标是什么。我正在尝试以HTML形式创建一系列列表:

<div>
    <h3>Math K</h3>
    <li>Counting & Cardinality</li>
    <li>Geometry</li>
</div>
<div>
    <h3>Math 1</h3>
    <li>Counting & Cardinality</li>
    <li>Orders of Operation</li>
</div>
<div>
    <h3>Math 2</h3>
    <li>Geometry</li>
</div>

我最初的想法是创建一个数组,然后将其推入<div>页面中的元素中。$("#divid").append(array)


阅读 595

收藏
2020-05-01

共1个答案

一尘不染

最终,我需要一个列表,其中每个唯一的等级作为标题,唯一的域作为列表项,以传递到HTML页面中。我可能会犯错,因此,如果有更简单的方法来实现最终目标,则可以公开征求意见。

因此,您实际上并不需要您所要求的格式的输出数组。

在这种情况下,我将通过一个非常简单有效的解决方案直接进行追赶:

var grades = {};
standardsList.forEach( function( item ) {
    var grade = grades[item.Grade] = grades[item.Grade] || {};
    grade[item.Domain] = true;
});

console.log( JSON.stringify( grades, null, 4 ) );

结果grades对象是:

{
    "Math K": {
        "Counting & Cardinality": true,
        "Geometry": true
    },
    "Math 1": {
        "Counting & Cardinality": true,
        "Orders of Operation": true
    },
    "Math 2": {
        "Geometry": true
    }
}

这种方法的有趣之处在于它非常快。请注意,它仅对输入数组进行一次遍历,这与其他需要多次遍历的解决方案不同(无论您是自己编写还是_.uniq()为您自己编写)。对于少量商品,这无关紧要,但是对于较大的商品,请记住这一点。

有了这个对象,您现在拥有了运行任何代码或生成所需任何其他格式所需的一切。例如,如果确实需要您提到的确切数组输出格式,则可以使用:

var outputList = [];
for( var grade in grades ) {
    for( var domain in grades[grade] ) {
        outputList.push({ Grade: grade, Domain: domain });
    }
}

JSON.stringify( outputList, null, 4 );

这将记录:

[
    {
        "Grade": "Math K",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math K",
        "Domain": "Geometry"
    },
    {
        "Grade": "Math 1",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math 1",
        "Domain": "Orders of Operation"
    },
    {
        "Grade": "Math 2",
        "Domain": "Geometry"
    }
]

Rai在评论中询问此代码行的工作方式:

var grade = grades[item.Grade] = grades[item.Grade] || {};

这是获取对象属性或缺少属性时提供默认值的常见用法。请注意,=分配是按从右到左的顺序进行的。因此,我们可以按字面意义将其翻译为使用一条if语句和一个temp变量:

// Fetch grades[item.Grade] and save it in temp
var temp = grades[item.Grade];
if( ! temp ) {
    // It was missing, so use an empty object as the default value
    temp = {};
}
// Now save the result in grades[item.Grade] (in case it was missing)
// and in grade
grades[item.Grade] = temp;
var grade = temp;

您可能会注意到,在grades[item.Grade]已经存在的情况下,我们采用刚刚获取的值,并将其存储回相同的属性中。当然,这是不必要的,如果您像这样编写代码,则可能不会这样做。相反,您可以简化它:

var grade = grades[item.Grade];
if( ! grade ) {
    grade = grades[item.Grade] = {};
}

那将是编写相同代码的完全合理的方法,并且效率也更高。与||成语所依赖的“真实性”相比,它还为您提供了一种更具体的测试方法。例如,if( ! grade )您可能想使用而不是if( grade === undefined )

2020-05-01