Map relationship between array objects

Given the JSON of various Pokemon battles:

 [
    {
        "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"
      }
    ]
  }
]

      

I want to display a grid counting the number of matches between two Pokemon trainers / players. One match can have up to 4 players at the same time.

            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

      

My code:

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

      

I'm looking for advice if I can do this better in vanilla JS / with third party libraries. How can I make this efficient enough to handle a lot of combat data (millions).

+3


source to share


2 answers


First, you can get the names of the unique players, and then create an object for each player, which takes as its value another object with the names of each player, including yourself. Then you just need to loop over your data and increment the values ​​of that object and finally create the table.



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;
}
      

<table></table>
      

Run code


0


source


With a 2D map structure, you can do it like this; This code will return you a card in which each key (player name) contains another card containing names and the number of matches carried out with competitors.



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));
      

Run code


0


source







All Articles