【问题标题】:Map relationships between Array Objects数组对象之间的映射关系
【发布时间】:2017-09-03 16:19:16
【问题描述】:

鉴于各种口袋妖怪对战的 JSON:

 [
    {
        "battleID": "1",
        "trainers": [
            {
                "LastName": "Ketchum",
                "ForeName": "Ash"
      },
            {
                "LastName": "Mason",
                "ForeName": "Misty"
      }
    ]
  },
    {
        "battleID": "2",
        "trainers": [
            {
                "LastName": "Mason",
                "ForeName": "Misty"
      },
            {
                "LastName": "Brock",
                "ForeName": "Stuart"
      },
            {
                "LastName": "Ian",
                "ForeName": "Foster"
      }
    ]
  },
    {
        "battleID": "3",
        "trainers": [
            {
                "LastName": "Brock",
                "ForeName": "Stuart"
      },
            {
                "LastName": "Ketchum",
                "ForeName": "Ash"
      }
    ]
  }
]

我想绘制一个网格来计算两个口袋妖怪训练师/玩家之间的比赛次数。一场比赛最多可以同时有 4 名玩家。

            Ash Ketchum     Misty Mason     Brock Stuart        Ian Foster
Ash Ketchum      2               1               1                  0

Misty Mason      1               2               1                  1

Brock Stuart     1               1               2                  1

Ian Foster       0               1               1                  1

我的代码:

class Trainer {
constructor(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

coBattles(trainer) {
    var battles = 0;
    jsonData.map(x => {
        x.trainers.map(y => {
            if (this.firstname === y.ForeName && this.lastname === y.LastName) {
                x.trainers.map(z => {
                    if (trainer.firstname === z.ForeName && trainer.lastname === z.LastName)
                        battles++;
                });
            }
        });
    });
    return battles;
}

}

var pokemonTrainers = [];

// Currently Undesirable as I want a 'unique' array of all participating trainers. 
jsonData.forEach(x => {
    x.trainers.forEach(y => {
        var trainer = new Trainer(y.ForeName, y.LastName);
        pokemonTrainers.push(trainer);
    });
});

//Battles between Misty Mason and Brock Stuart
console.log(pokemonTrainers[1].coBattles(pokemonTrainers[3]));
//returns 1

我正在寻找有关是否可以在 vanilla JS/ 中使用第三方库做得更好的建议。我怎样才能让它足够高效地处理大量的战斗数据(数百万)。

【问题讨论】:

  • 只是一个注释,Array.map/forEach 和其他内置函数目前比 V8 中的普通 for 循环慢(Chrome 和 Node,js)

标签: javascript arrays json algorithm object


【解决方案1】:

使用 2D 地图结构,您可以执行以下操作;此代码将返回一个地图,其中每个键(玩家姓名)都包含另一个地图,其中包含名称和与竞争对手的比赛次数。

function getPlayedMatches(a){
  return a.reduce(function(r,b){
                    var nl = b.trainers.map(t => t.ForeName + " " + t.LastName);
                    return nl.reduce((m,tn) => m.has(tn) ? m.set(tn, nl.reduce((sm,t) => sm.has(t) ? sm.set(t,sm.get(t)+1)
                                                                                                   : sm.set(t,1), m.get(tn)))
                                                         : m.set(tn,new Map(nl.map(n => [n,1]))), r);
                  }, new Map);
}

var matches = [{"battleID":"1","trainers":[{"LastName":"Ketchum","ForeName":"Ash"},{"LastName":"Mason","ForeName":"Misty"}]},{"battleID":"2","trainers":[{"LastName":"Mason","ForeName":"Misty"},{"LastName":"Brock","ForeName":"Stuart"},{"LastName":"Ian","ForeName":"Foster"}]},{"battleID":"3","trainers":[{"LastName":"Brock","ForeName":"Stuart"},{"LastName":"Ketchum","ForeName":"Ash"}]}],
     result = getPlayedMatches(matches);
console.log(function arrayifyMap(m){
                       return m.constructor === Map ? [...m].map(([v,k]) => [arrayifyMap(v),arrayifyMap(k)])
                                                    : m;
              }(result));

【讨论】:

    【解决方案2】:

    您可以首先获取所有唯一玩家的姓名,然后为每个玩家构建对象,该对象作为值具有另一个对象,其中包含每个玩家的姓名,包括他自己。然后你只需要循环你的数据并增加该对象的值,最后构建表。

    var data =  [{"battleID":"1","trainers":[{"LastName":"Ketchum","ForeName":"Ash"},{"LastName":"Mason","ForeName":"Misty"}]},{"battleID":"2","trainers":[{"LastName":"Mason","ForeName":"Misty"},{"LastName":"Brock","ForeName":"Stuart"},{"LastName":"Ian","ForeName":"Foster"}]},{"battleID":"3","trainers":[{"LastName":"Brock","ForeName":"Stuart"},{"LastName":"Ketchum","ForeName":"Ash"}]}]
    
    var players = {}
    var result = {}
    
    // Get all names
    data.forEach(function(e) {
      e.trainers.forEach(function(p) {
        players[p.LastName + ' ' + p.ForeName] = 1
      })
    })
    
    // Add to result object
    Object.keys(players).forEach(function(name) {
      Object.keys(players).forEach(function(e) {
        result[name] = Object.assign(result[name] || {}, {[e]: 0})
      })
    })
    
    // Increment values
    data.forEach(function(e) {
      e.trainers.forEach(function(a, j) {
        e.trainers.forEach(function(c, i) {
          result[a.LastName + ' ' + a.ForeName][c.LastName + ' ' + c.ForeName]++
        })
      })
    })
    
    var table = document.body.querySelector('table');
    var thead = '<tr><td></td><td>' + Object.keys(result).join('</td><td>') + '</td></tr>';
    table.innerHTML += thead
    
    for (var key in result) {
      var cells = '';
      for (var i in result[key]) {
        cells += '<td>' + result[key][i] + '</td>';
      }
    
      var row = '<tr><td>' + key + cells + '</td></tr>';
      table.innerHTML += row;
    }
    td:not(:first-child) {
      text-align: center;
    }
    &lt;table&gt;&lt;/table&gt;

    【讨论】:

    • 泰!虽然,我担心这在大量战斗中的表现如何。您如何看待缓存结果? Misty 和 Ash 之间的战斗将与 Ash 和 Misty 之间的战斗相同。另外,如何记录玩家第一次参与循环的战斗,以便我们只在计算其他参与者时挑选那些战斗?
    • 是的,我认为有一些更有效的解决方案,这确实使用了很多循环。如果您不必为每个玩家显示每个玩家,而是只显示相互战斗的玩家,我认为这会简单得多。
    • 能否请您详细说明一下如何更简单?
    • 我猜你可以跳过我的代码中的第一步并结合第二和第三步,但我不确定。
    猜你喜欢
    • 1970-01-01
    • 2011-04-24
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多