javascript 使用 AngularJS 比较两个对象数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31126021/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two arrays of objects using AngularJS
提问by Aaron Minnamon
I am having an issue with comparing two arrays. One is a fixed data set while the other is being generated dynamically.
我在比较两个数组时遇到问题。一个是固定的数据集,而另一个是动态生成的。
A sample of the two arrays are as follows:
两个数组的示例如下:
// Fixed list of 197 countries
$scope.countries = [
{"name": "Afghanistan", "code": "AF"},
{"name": "Albania", "code": "AF"},
{"name": "Algeria", "code": "AF"},
//...
{"name": "Zimbabwe", "code": "ZW"}
];
//Dynamically generated list of matched countries
$scope.matches = [
{"name": "Belgium"},
{"name": "Ghana"}
];
At the end of the game a function will be run and a comparison of the two arrays will be made. As of right now I have tried (What seems like) almost every combination of this compare using angular.forEach and standard javascript loops. The issue comes when I try to log what countries haven't been matched.
在游戏结束时,将运行一个函数并对两个数组进行比较。到目前为止,我已经尝试过(看起来像什么)使用 angular.forEach 和标准 javascript 循环进行比较的几乎所有组合。当我尝试记录哪些国家/地区未匹配时,问题就出现了。
This is the compare function I am running.
这是我正在运行的比较功能。
$scope.compareArrays = function(){
angular.forEach($scope.countries, function(country,name){
angular.forEach($scope.matches, function(match){
if (country.name !== match.name) {
console.log(country.name);
} else {
console.log("MATCHED");
}
});
});
};
The function will find and log the countries that havent been matched...but it is logging the entire list of unmatched countries multiple times. Specifically once for every object in the "matches" array.
该函数将查找并记录未匹配的国家/地区...但它多次记录未匹配国家/地区的整个列表。特别是对“matches”数组中的每个对象一次。
So for example if the matches array is the same as the sample above, it will log the unmatched countries list twice once with Belgium logging as "MATCHED" and the other time logging Belgium as an unmatched country (Same for Ghana but reversed obviously).
因此,例如,如果matches数组与上面的示例相同,它将记录两次未匹配的国家列表,其中比利时将记录为“MATCHED”,另一次将比利时记录为未匹配的国家(与加纳相同,但显然相反)。
I simply want it to log a list of the unmatched countries once and that is all.
我只是想让它记录一次不匹配国家的列表,仅此而已。
I'm hoping it is a simple oversight but cannot figure it out. Thank you in advance.
我希望这是一个简单的疏忽,但无法弄清楚。先感谢您。
回答by ccjmne
What you're doing here is (pseudo-code):
你在这里做的是(伪代码):
for each existing country
for each country to be matched
log country.name UNLESS it's a match
The thing is, even if all your existing countries AREin the matches
list, each of your 197 existing countrieswill NOTmatch any of the 196 other.
问题是,即使所有现有的国家现在在matches
列表中,每个197个现有的国家将不匹配任何其他的196。
You actually need to be sure that each country
(from the countries
list) is not matched by ANYof the countries from matches
: then and only then, it's actually an "unmatched" country.
您实际上需要确保每个country
(来自countries
列表)都没有与以下任何国家/地区匹配matches
:只有这样,它实际上是一个“无法匹配”的国家/地区。
Here's a nice way to get that list (using Underscore.js, which I highly recommend):
这是获取该列表的好方法(使用我强烈推荐的Underscore.js):
// Fixed list of 197 countries
var countries = [
{"name": "Afghanistan", "code": "AF"},
{"name": "Albania", "code": "AF"},
{"name": "Algeria", "code": "AF"},
{"name": "Zimbabwe", "code": "ZW"}
];
// Dynamically generated list of matched countries
var matches = [
{"name": "Albania"},
{"name": "Ghana"}
];
// Rejecting the countries that have "some" (at least one) match in the other list.
function compareArrays(countries, matches){
return _.reject(countries, function(country) {
return _.some(matches, function(match) {
return country.name === match.name;
});
});
};
_.each(compareArrays(countries, matches), function(unmatched) {
console.log(unmatched);
});
// Object {name: "Afghanistan", code: "AF"}
// Object {name: "Algeria", code: "AF"}
// Object {name: "Zimbabwe", code: "ZW"}
And here is a link to a working JSFiddle.
这是一个指向工作 JSFiddle的链接。
Note that I haven't used any Angular stuff in that answer because it that problem is actually purely algorithmic related.
请注意,我没有在该答案中使用任何 Angular 内容,因为该问题实际上与算法有关。
回答by NiklasMH
I guess you can skip counting the duplicated checks by somehow start the second loop where the first one currently is. I would have done this with an index and a for-loop:
我想您可以通过以某种方式启动当前第一个循环的第二个循环来跳过对重复检查的计数。我会用一个索引和一个 for 循环来做到这一点:
$scope.compareArrays = function(){
var c = $scope.countries;
var m = $scope.matches;
for(var i = 0;i < c.length;i++) {
for(var j = i;j < m.length;j++) { // Notice the j = i;
if (c[i].name !== m[j].name) {
console.log(c[i].name);
} else {
console.log("MATCHED");
}
};
});
};
I hope this answered your question, and hope you like plain JS too!
我希望这能回答你的问题,也希望你也喜欢普通的 JS!
回答by r-park
You should break it up into smaller functions. For example, create a comparison function which will return true
if country
is not in your matches
list:
你应该把它分解成更小的函数。例如,创建一个比较函数,true
如果country
不在您的matches
列表中,它将返回:
function isUnmatched(country, matches) {
return matches.every(function(matched){
return country.name !== matched.name;
});
}
Then create a function that will call isUnmatched
for each country and return an array of unmatched countries:
然后创建一个函数,该函数将为isUnmatched
每个国家/地区调用并返回一组不匹配的国家/地区:
function getUnmatched() {
return countries.filter(function(country){
return isUnmatched(country, matches);
});
}
If your environment doesn't support Array.prototype.every
and Array.prototype.filter
, you can re-write the above as follows:
如果你的环境不支持Array.prototype.every
and Array.prototype.filter
,你可以按照下面的方式重写上面的:
function isUnmatched(country, matches) {
var i = matches.length;
while (i--) {
if (country.name === matches[i].name) {
return false;
}
}
return true;
}
function getUnmatched() {
var unmatched = [],
i = countries.length,
country;
while (i--) {
country = countries[i];
if (isUnmatched(country, matches)) {
// console.log(country.name)
unmatched.push(country);
}
}
return unmatched;
}
So if your lists look like this:
因此,如果您的列表如下所示:
var countries = [
{"name": "Afghanistan", "code": "AF"},
{"name": "Albania", "code": "AF"},
{"name": "Algeria", "code": "AF"}
];
var matches = [
{"name": "Albania"},
{"name": "Algeria"}
];
Then:
然后:
var unmatched = getUnmatched();
//=> [{"name": "Afghanistan", "code": "AF"}]
回答by skyboyer
put all the names from
matches
list into a hash as a key:var index = {}; matches. forEach(name => index [name] = true;)
iterate through
countries
and check if current one exist inindex
:for (let country of countries) if (!index.hasOwnProperty(country. name)) console.log(country.name, ' is not included');
get O(N+M) instead of O(N*M)
将
matches
列表中的所有名称作为键放入散列中:变量索引 = {}; 火柴。forEach(name => index [name] = true;)
迭代
countries
并检查当前是否存在于index
:for (let country of countries) if (!index.hasOwnProperty(country.name)) console.log(country.name, ' is not included');
得到 O(N+M) 而不是 O(N*M)