Skip to content
Advertisement

limit the array length by 2 data only

I am currently making a matchmaking system. My target is to limit the array length by 2 data only. In my current work, when I add another data with the same level, it becomes 3 data in 1 array (Please see pic 1). When there’s 3 data in 1 array, send the extra 1 data to another array until it gets a player to match with. The matching works when players have the same level. I have provided my codes below and a screenshot. Any help will be appreciated. Thank you.

enter image description here

const source = [{
    id: 1,
    name: 'player1',
    level: 1
  },
  {
    id: 2,
    name: 'player2',
    level: 1
  },
  {
    id: 3,
    name: 'player3',
    level: 2
  },
  {
    id: 4,
    name: 'player4',
    level: 2
  },
  {
    id: 5,
    name: 'player5',
    level: 1
  },
  {
    id: 6,
    name: 'player6',
    level: 3
  },
  {
    id: 7,
    name: 'player7',
    level: 3
  },



]
const combine = (source) => {
  return source.reduce((acc, curr) => {
    if (acc[curr.level])
      acc[curr.level].push(curr);
    else
      acc[curr.level] = [curr];
    return acc;
  }, {})
}
var result = combine(source)
var html = ""
var keys = Object.keys(result) //if there more then one keys i.e : 2..

for (var i = 0; i < keys.length; i++) {
  console.log("Keys " + keys[i])
  //loop through json array
  result[keys[i]].forEach(function(val, index) {
  //check if index value is `0`..change name. 
    var ids = index == 0 ? "id[]" : "idside[]"
    var name = index == 0 ? "name[]" : "nameside[]"
    var levels = index == 0 ? "level[]" : "levelside[]"
    html += `<input type="text" name="${ids}" value="${val.id}">
<input type="text" name="${name}" value="${val.name}">
<input type="text" name="${levels}" value="${val.level}">`
  })
}
document.getElementById("result").innerHTML = html //add html to div

console.log(result);
<div id="result">
</div>

Advertisement

Answer

You can accumulate into a 2d array by level and check if the currently accumulated array length is 2.

const
  source = [{ id: 1, name: 'player1', level: 1 }, { id: 2, name: 'player2', level: 1 }, { id: 3, name: 'player3', level: 2 }, { id: 4, name: 'player4', level: 2 }, { id: 5, name: 'player5', level: 1 }, { id: 6, name: 'player6', level: 3 }, { id: 7, name: 'player7', level: 3 },];

const combine = (source) => {
  return source.reduce((acc, curr) => {
    if (acc[curr.level]) {
      const levelArr = acc[curr.level];
      const last = levelArr[levelArr.length - 1];
      if (last.length === 2) {
        levelArr.push([curr])
      } else {
        last.push(curr);
      }
    }
    else {
      acc[curr.level] = [[curr]];
    }
    return acc;
  }, {})
};

const result = combine(source)

// HTML generation
const matchesUl = document.createElement('ul');

Object.entries(result).forEach(([key, level]) => {
  const levelLi = document.createElement('li');
  const title = document.createTextNode(`Level ${key}`);
  levelLi.appendChild(title);
  const levelUl = document.createElement('ul');
  levelLi.appendChild(levelUl);
  level.forEach(match => {
    const [p1, p2] = match;
    const matchLi = document.createElement('li');
    matchLi.textContent = `${p1.name} vs. ${p2?.name ?? '-'}`;
    levelUl.appendChild(matchLi);
  })
  matchesUl.appendChild(levelLi);
})

document.getElementById("result").appendChild(matchesUl); //add html to div

// Debug
const pre = document.createElement('pre')
pre.innerHTML = JSON.stringify(result, null, 2);

document.getElementById('debug').appendChild(pre);
 #debug {
    border: 1px solid darkgray;
    background-color: lightgray;
    padding: 1rem;
    margin-top: 1rem;
  }
<div id="result">
</div>

<div id="debug">
  <p>Output</p>
</div>

If you only want complete combinations you can track individual players in an unmatched object and only add them to their applicable level array when a match is found. You will still end up with a 2D array for each level, but all sub-arrays will be matched pairs.

const
  source = [{ id: 1, name: 'player1', level: 1 }, { id: 2, name: 'player2', level: 1 }, { id: 3, name: 'player3', level: 2 }, { id: 4, name: 'player4', level: 2 }, { id: 5, name: 'player5', level: 1 }, { id: 6, name: 'player6', level: 3 }, { id: 7, name: 'player7', level: 3 }, { id: 8, name: 'player8', level: 3 }];

const combine = (source) => {
  return source.reduce((acc, curr) => {
    if (acc[curr.level]) {
      if (acc.unmatched[curr.level]) {
        acc[curr.level].push([acc.unmatched[curr.level], curr])
        acc.unmatched[curr.level] = null;
      } else {
        acc.unmatched[curr.level] = curr;
      }
    }
    else {
      acc[curr.level] = [];
      acc.unmatched[curr.level] = curr;
    }
    return acc;
  }, { unmatched: {} })
};

const result = combine(source)

// HTML Generation
const matchesUl = document.createElement('ul');

Object.entries(result).forEach(([key, level]) => {
  if (key !== 'unmatched') {
    const levelLi = document.createElement('li');
    const title = document.createTextNode(`Level ${key}`);
    levelLi.appendChild(title);
    const levelUl = document.createElement('ul');
    levelLi.appendChild(levelUl);
    level.forEach(match => {
      const [p1, p2] = match;
      const matchLi = document.createElement('li');
      matchLi.textContent = `${p1.name} vs. ${p2?.name ?? '-'}`;
      levelUl.appendChild(matchLi);
    });
    matchesUl.appendChild(levelLi);
  }
});

const unmatchedLi = document.createElement('li');
const title = document.createTextNode('Unmatched');
unmatchedLi.appendChild(title);
const unmatchedUl = document.createElement('ul');
unmatchedLi.appendChild(unmatchedUl);
Object.values(result.unmatched).forEach(player => {
  if (player) {
    const li = document.createElement('li');
    li.textContent = `${player.name} (lvl ${player.level})`;
    unmatchedUl.appendChild(li);
  }
});
matchesUl.appendChild(unmatchedLi)

document.getElementById("result").appendChild(matchesUl); //add html to div

// Debug
const pre = document.createElement('pre')
pre.innerHTML = JSON.stringify(result, null, 2);

document.getElementById('debug').appendChild(pre);
#debug {
    border: 1px solid darkgray;
    background-color: lightgray;
    padding: 1rem;
    margin-top: 1rem;
  }
<div id="result">
</div>

<div id="debug">
  <p>Output</p>
</div>
Advertisement