Сравнение двух массивов объектов с использованием AngularJS

0

У меня проблема со сравнением двух массивов. Один из них представляет собой фиксированный набор данных, а другой генерируется динамически.

Образец из двух массивов выглядит следующим образом:

// 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", а другое время регистрирует Бельгию как страну непревзойденной (то же самое для Ганы, но наоборот).

Я просто хочу, чтобы он регистрировал список непревзойденных стран один раз, и это все.

Я надеюсь, что это простой надзор, но он не может понять. Заранее спасибо.

Теги:
arrays
nested-loops
foreach

4 ответа

0
  1. поместите все имена из списка matches в хэш как ключ:

    var index = {}; Матчи. forEach (name => index [name] = true;)

  2. перебирать по countries и проверять, существует ли текущий index в index:

    для (пусть страна стран) если (! index.hasOwnProperty (страна. имя)) console.log (страна.имя, 'не входит');

  3. получить O (N + M) вместо O (N * M)

0

Что вы здесь делаете (псевдокод):

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.


Обратите внимание, что я не использовал в этом ответе какие-либо угловые вещи, потому что эта проблема на самом деле является чисто алгоритмической.

0

Я думаю, вы можете пропустить подсчет дублированных проверок, чтобы как-то запустить второй цикл, где первый в настоящий момент. Я бы сделал это с индексом и для цикла:

$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!

0

Вы должны разбить его на более мелкие функции. Например, создайте функцию сравнения, которая вернет 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"}]

JSFiddle 1
JSFiddle 2

Ещё вопросы

Сообщество Overcoder
Наверх
Меню