Stop duplicates in an array

Viewed 76

Problem has been solved

What I need is if I declare n as 4. I need 4 unique coordinates and push them to array, here is my code that can produce duplicates:

function entriesToDel(n) {

        var array = [];

        for (let i = 0; i < array.length; i++) {
            var row = Math.round(3*Math.random());
            var col = Math.round(3*Math.random());
            var output = [row,col]; 
            array.push(output);

    }

    return array;
}
6 Answers

What you can do is simply put a condition based checking for the coords.

e.g. You can do something like,

function entriesToDel(n) {

    var array = [];

    for (var i = 0; i < n; i++) {
        const repeat = () => {
            var row = Math.round(3 * Math.random());
            var col = Math.round(3 * Math.random());
            var coords = [row, col];

            let sameEntry = array.find(i => i[0] === row && i[1] === col)
            if (sameEntry) {
                repeat();
            } else {
                array.push(coords);
            }
        }
        repeat();
    }
    console.log(array);
    return array;
}

Instead of creating the coordinates randomly, shuffle an array with all 3x3 coordinates and pick the first n of them:

function shuffle(a) { // Generic shuffle function
    for (let i = a.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        let x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
    return a;
}

function entriesToDel(n) {
    // Generate all possible coordinates in a 3x3 grid
    let coord = Array.from({length: 3}, (_, i) =>
        Array.from({length: 3}, (_, j) => [i, j])
    ).flat();
    
    // Shuffle and select
    return shuffle(coord).slice(0, n);
}

console.log(entriesToDel(4));

You can just change your for loop into a while loop, and just terminate when the array.length is equal to your parameter.

You can use Arrray.some() to check if you already have the coordinate.

eg.

function entriesToDel(n) {
    var array = [];
    while (array.length < n) {
        var row = Math.round(3*Math.random());
        var col = Math.round(3*Math.random());
        var coords = [row,col]; 
        if (!array.some(([r,c]) => 
           r === row && c === col))
              array.push(coords);
    }
    return array;
}

console.log(entriesToDel(4));

You can also try use my solution. I use new Map to easly and fast get, set and check but you can use plain object instead of it

const entriesToDel = (coordsCount) => {

    const coordsArr = [];
    const coordsMap = new Map();

    for (let i = 0; i < coordsCount; ++i) {

        const row = Math.round(3 * Math.random());
        const col = Math.round(3 * Math.random());
        
        if (!coordsMap.has(row)) {
            coordsMap.set(row, [col]);
            coordsArr.push([row, col]);
        } else {
            const cols = coordsMap.get(row);
            
            if (!cols.includes(col)) {
                cols.push(col);
                console.log(coordsMap);
                coordsArr.push([row, col]);
                continue;
            }
            
            --i;
        }
    }

    return coordsArr;
}

console.log(entriesToDel(4));

I think a good approach is using a map (object). You can create an id for each coords array and check if you previously found it, then iterate n times.

function entriesToDel(n) {
    var map = {};
   
    while (i < n) {
      var row = Math.round(3*Math.random());
      var col = Math.round(3*Math.random());
      var coords = [row,col];
      var coordsId = `${row}${col}`;
      if (!map[coordsId]) {
        map[coordsId] = coords;
        i++;
      }
      
    }
    var array = Object.values(map);
    return array;
}

To make it more readable I'd create another function to check if the array already contains the generated coordinates.

function arrayIncludesCoords(arr, [row, col]) {
  return arr.some(([r,c]) => r === row && c === col)
}

function entriesToDel(n) {
  const array = [];
  while (array.length < n) {
    const row = Math.round(3 * Math.random());
    const col = Math.round(3 * Math.random());
    const coords = [row, col];
    if (!arrayIncludesCoords(array, coords)) {
      array.push(coords);
    }
  }
  return array;
}

console.log(entriesToDel(4))

Note that you should guarantee not to pass an n value so big that there aren't enough different pairs of coordinates to fill the array. That'd lead to an infinite loop.

Related