使用AngularJS比较两个对象数组

问题描述 投票:0回答:4

我在比较两个数组时遇到问题。一个是固定数据集,而另一个是动态生成的。

两个数组的示例如下:

// 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"}
];

在游戏结束时,将运行一个函数并对两个数组进行比较。截至目前,我已经尝试过(看起来像)使用angular.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”数组中的每个对象。

因此,例如,如果匹配数组与上面的示例相同,它将两次登录不匹配的国家/地区列表,其中比利时登录为“匹配”,另一次将比利时记录为不匹配的国家(加纳相同但明显逆转)。

我只想让它记录一次不匹配的国家名单,这就是全部。

我希望这是一个简单的疏忽,但无法弄清楚。先感谢您。

javascript arrays angularjs foreach nested-loops
4个回答
0
投票

你在这里做的是(伪代码):

for each existing country
    for each country to be matched
        log country.name UNLESS it's 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"}

这里有一个working JSFiddle的链接。


请注意,我没有在该答案中使用任何Angular内容,因为该问题实际上与算法有关。


0
投票

我猜你可以跳过计算重复的检查,以某种方式启动当前第一个循环。我会用索引和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");
      }
    };
  });
};

我希望这能回答你的问题,并希望你也喜欢普通的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.everyArray.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


0
投票
  1. matches列表中的所有名称放入哈希作为键: var index = {};火柴。 forEach(name => index [name] = true;)
  2. 迭代countries并检查index中是否存在当前的: for(let country of countries)if(!index.hasOwnProperty(country.name))console.log(country.name,'not included');
  3. 得到O(N + M)而不是O(N * M)
© www.soinside.com 2019 - 2024. All rights reserved.