У меня проблема со сравнением двух массивов. Один из них представляет собой фиксированный набор данных, а другой генерируется динамически.
Образец из двух массивов выглядит следующим образом:
// 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"}
];
В конце игры будет запущена функция, и будет выполнено сравнение двух массивов. На данный момент я попробовал (что-то вроде) почти каждую комбинацию этого сравнения, используя угловые. ForEach и стандартные javascript-циклы. Проблема возникает, когда я пытаюсь зарегистрировать, какие страны не были сопоставлены.
Это функция сравнения, которую я запускаю.
$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");
}
});
});
};
Функция найдет и зарегистрирует страны, которые не были сопоставлены... но она регистрирует весь список несогласованных стран несколько раз. В частности, один раз для каждого объекта в массиве "matches".
Так, например, если массив совпадений совпадает с примером, указанным выше, он будет регистрировать список несогласованных стран дважды один раз, когда Бельгия регистрируется как "MATCHED", а другое время регистрирует Бельгию как страну непревзойденной (то же самое для Ганы, но наоборот).
Я просто хочу, чтобы он регистрировал список непревзойденных стран один раз, и это все.
Я надеюсь, что это простой надзор, но он не может понять. Заранее спасибо.
поместите все имена из списка matches
в хэш как ключ:
var index = {}; Матчи. forEach (name => index [name] = true;)
перебирать по countries
и проверять, существует ли текущий index
в index
:
для (пусть страна стран) если (! index.hasOwnProperty (страна. имя)) console.log (страна.имя, 'не входит');
получить O (N + M) вместо O (N * M)
Что вы здесь делаете (псевдокод):
for each existing country
for each country to be matched
log country.name UNLESS it a match
Дело в том, что даже если все существующие странах находятся в matches
списке, каждый из ваших 197 существующих стран не соответствует ни одному из 196 других.
Вы действительно должны быть уверены, что каждая country
(из списка countries
) не соответствует ЛЮБОЙ из стран из matches
: тогда и только тогда она фактически является "непревзойденной" страной.
Здесь хороший способ получить этот список (используя 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"}
И вот ссылка на рабочий JSFiddle.
Обратите внимание, что я не использовал в этом ответе какие-либо угловые вещи, потому что эта проблема на самом деле является чисто алгоритмической.
Я думаю, вы можете пропустить подсчет дублированных проверок, чтобы как-то запустить второй цикл, где первый в настоящий момент. Я бы сделал это с индексом и для цикла:
$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");
}
};
});
};
Надеюсь, это ответ на ваш вопрос, и надеюсь, вам понравится просто JS!
Вы должны разбить его на более мелкие функции. Например, создайте функцию сравнения, которая вернет true
если country
не находится в вашем списке matches
:
function isUnmatched(country, matches) {
return matches.every(function(matched){
return country.name !== matched.name;
});
}
Затем создайте функцию, которая будет вызывать isUnmatched
для каждой страны и возвращает массив непревзойденных стран:
function getUnmatched() {
return countries.filter(function(country){
return isUnmatched(country, matches);
});
}
Если ваша среда не поддерживает Array.prototype.every
и 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;
}
Поэтому, если ваши списки выглядят так:
var countries = [
{"name": "Afghanistan", "code": "AF"},
{"name": "Albania", "code": "AF"},
{"name": "Algeria", "code": "AF"}
];
var matches = [
{"name": "Albania"},
{"name": "Algeria"}
];
Затем:
var unmatched = getUnmatched();
//=> [{"name": "Afghanistan", "code": "AF"}]