我有一个看起来像这样的数组:
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在对象中出现一对时才起作用。我似乎无法使它跨多个键工作。
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)
<div>
$("#divid").append(array)
因此,您实际上并不需要您所要求的格式的输出数组。
在这种情况下,我将通过一个非常简单有效的解决方案直接进行追赶:
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对象是:
grades
{ "Math K": { "Counting & Cardinality": true, "Geometry": true }, "Math 1": { "Counting & Cardinality": true, "Orders of Operation": true }, "Math 2": { "Geometry": true } }
这种方法的有趣之处在于它非常快。请注意,它仅对输入数组进行一次遍历,这与其他需要多次遍历的解决方案不同(无论您是自己编写还是_.uniq()为您自己编写)。对于少量商品,这无关紧要,但是对于较大的商品,请记住这一点。
_.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变量:
=
if
// 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]已经存在的情况下,我们采用刚刚获取的值,并将其存储回相同的属性中。当然,这是不必要的,如果您像这样编写代码,则可能不会这样做。相反,您可以简化它:
grades[item.Grade]
var grade = grades[item.Grade]; if( ! grade ) { grade = grades[item.Grade] = {}; }
那将是编写相同代码的完全合理的方法,并且效率也更高。与||成语所依赖的“真实性”相比,它还为您提供了一种更具体的测试方法。例如,if( ! grade )您可能想使用而不是if( grade === undefined )。
||
if( ! grade )
if( grade === undefined )