Finding duplicate max values in a matrix

264 views Asked by At

What I'm working with is a matrix of objects and I'm trying to find the maximum values for each of the objects, including duplicates.

Here's what I have until now:

        let findColumnMaxValue = (i) => {
         let coord = [];
         let maxValue = 0;
         for (let j = 0; j < this.field.length; j++) {
            if (this.field[i][j].dst > maxValue) {
                maxValue = this.field[i][j].dst;
            }
        }

        getMaxValueCoord(maxValue, coord, i);
        return coord;
    }

Up here I'm finding the maximum value for every row of each column.

        let getMaxValueCoord = (max, a, i) => {
         for (let j = 0; j < this.field.length; j++) {
            if (this.field[i][j].dst === max) {
                a.push({x: i, y: j})
            }
        }
    }

and in this function, after finding the max, I'm comparing each row of each column to the max value and pushing the object coordinates into an array if it meets the condition.

    findHighestDensityCells() {
     let arr = []; 
     for (let i = 0; i < this.field.length; i++) {
         arr.push(findColumnMaxValue(i));
     }

     return [].concat(...arr);
}

Now that I have an array of all the max object value coordinates for each column, I want this array to contain only the max values, including duplicates, basically repeating much of what I've done above.

What I've written above seems to take up too much code in order to solve this simple problem. Are there other methods I could use to help reduce the amount of code?

EDIT

The data is a simple object options = { dst: 0 } with a value that gets updated by another function. Therefore the rows within the columns all contain the above object, each with different values. So my matrix could look like this:

 2 3 4 5 6 6 5 4 3 2
 3 4 5 6 7 7 6 5 4 3
 4 5 6 7 8 8 7 6 5 4
 5 6 3 4 9 9 4 3 2 1
 6 7 3 4 9 9 4 3 2 1
 6 7 3 4 5 5 4 3 2 1
 5 6 3 4 5 5 4 3 2 1
 4 6 3 4 5 5 4 3 2 1
 3 5 3 4 5 5 4 3 2 1
 2 4 3 4 5 5 4 3 2 1

The desired result is getting all the maximum values within the matrix as coordinates including duplicates. In the example above this would be [9,9,9,9].

2

There are 2 answers

4
sergdenisov On BEST ANSWER

Check out some magic using Array.prototype.reduce(), arrow function expression, Math.max(), spread operator, Array.prototype.map(), Array.prototype.concat(), Array.prototype.filter():

const maxArray = matrix.reduce((maxArray, row, rowIndex) => {
  const max = Math.max(0, ...row.map(e => e.dst));

  return maxArray.concat(
    row.map(
      (e, i) => ({x: i, y: rowIndex, dst: e.dst})
    ).filter(e => e.dst === max)
  );
}, []);

const maxOfAll = Math.max(0, ...maxArray.map(e => e.dst));

const filteredMaxArray = maxArray.filter(
  e => e.dst === maxOfAll
).map(e => ({x: e.x, y: e.y}));

const matrix = [
  [{dst: 2}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 6}, {dst: 6}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}],
  [{dst: 3}, {dst: 4}, {dst: 5}, {dst: 6}, {dst: 7}, {dst: 7}, {dst: 6}, {dst: 5}, {dst: 4}, {dst: 3}],
  [{dst: 4}, {dst: 5}, {dst: 6}, {dst: 7}, {dst: 8}, {dst: 8}, {dst: 7}, {dst: 6}, {dst: 5}, {dst: 4}],
  [{dst: 5}, {dst: 6}, {dst: 3}, {dst: 4}, {dst: 9}, {dst: 9}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 6}, {dst: 7}, {dst: 3}, {dst: 4}, {dst: 9}, {dst: 9}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 6}, {dst: 7}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 5}, {dst: 6}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 4}, {dst: 6}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 3}, {dst: 5}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
  [{dst: 2}, {dst: 4}, {dst: 3}, {dst: 4}, {dst: 5}, {dst: 5}, {dst: 4}, {dst: 3}, {dst: 2}, {dst: 1}],
];

const maxArray = matrix.reduce((maxArray, row, rowIndex) => {
  const max = Math.max(0, ...row.map(e => e.dst));
  
  return maxArray.concat(
    row.map(
      (e, i) => ({x: i, y: rowIndex, dst: e.dst})
    ).filter(e => e.dst === max)
  );
}, []);

const maxOfAll = Math.max(0, ...maxArray.map(e => e.dst));

const filteredMaxArray = maxArray.filter(
  e => e.dst === maxOfAll
).map(e => ({x: e.x, y: e.y}));

console.log(filteredMaxArray);

0
Nina Scholz On

You could use a single function with only one loop over the outer array and inner array with a hash table for temporary max coordinates and with a collecting array for the result.

function getMax(data) {
    return data.reduce(function (r, a, x) {
        var hash = Object.create(null),
            max = 0;

        a.forEach(function (o, y) {
            if (max <= o.dst) {
                max = o.dst;
                hash[max] = hash[max] || [];
                hash[max].push({ x, y });
            }
        });
        return r.concat(hash[max]);
    }, []);
}

var data = [[{ dst: 1 }, { dst: 2 }, { dst: 3 }], [{ dst: 4 }, { dst: 5 }, { dst: 6 }], [{ dst: 7 }, { dst: 8 }, { dst: 9 }]]

console.log(getMax(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }