I want to compare values from objects that I keep in an array.

I know that I can create new arrays with values from each object but I'm trying to find some way to do it without creating them.

Consider we have such situation:

soldiers[first, second, third]
first{name: John, shooting: 95, combat: 50, tactic: 88}
second{name: Arnold, shooting: 97, combat: 72, tactic: 68}
third{name: William, shooting: 87, combat: 86, tactic: 97}

I'd like to select the best soldier from the provided above - but I can't create one rating (i.e. average).

There will be some conditions that soldier must fill - for example: at least 60 points in combat (no matter if every other property is 100).

So I'm trying to find way to compare multiple properties and return name of just one soldier.

I'll appreciate every tip. Thanks!

3 Answers

0
Tim VN On Best Solutions

I have made you an exmaple with comments. Let me know if this pushes you in the right direction or if you need any other help.

const soldiers = [{
    name: "John",
    shooting: 95,
    combat: 50,
    tactic: 88
  },
  {
    name: "Arnold",
    shooting: 97,
    combat: 72,
    tactic: 68
  },
  {
    name: "William",
    shooting: 87,
    combat: 86,
    tactic: 97
  }
];

const filteredSoldiers = soldiers
  .filter(soldier => soldier.combat > 60) // Find every soldier where combat is higher than 60
  .map(soldier => {
    return {
      name: soldier.name,
      average: (soldier.combat + soldier.tactic + soldier.shooting) / 3
    };
    // map will return an array with the filtered soldiers, and we put their average and their name in there
  })
  .sort((a, b) => b.average - a.average);
// Lastly we sort them high to low by their average score

console.log(
  filteredSoldiers.length > 0 ? filteredSoldiers[0].name : 'No soldiers with combat score higher thn 60'
);

jsfiddle

In the filter condition you can of course add more checks.

0
Ivan  Ivanov On

You need to got through all items and select best value;

Note that some soldiers can have similar values, that's why values.name is array

let a = {
    name: "John", shooting: 95, combat: 50, tactic: 88
};
let b = {
    name: "Arnold", shooting: 97, combat: 72, tactic: 68
};
let c = {
    name: "William", shooting: 87, combat: 86, tactic: 97
};
let soldiers = [a, b, c];
let values = {
    shooting: {
        name: [],
        score: 0
    },
    combat: {
        name: [],
        score: 0
    },
    tactic: {
        name: [],
        score: 0
    }
};

soldiers.map((item) => {
    ['shooting', 'combat', 'tactic'].forEach(name => {
        if (item[name] > values[name].score) {
            values[name].name = [item.name];
            values[name].score = item[name];
        } else if (item[name] === values[name].score) {
            values[name].name.push(item.name);
        }
    });
});

console.log(values);
0
Community On

Considering you have mentioned that not all skills are equally important, I would suggest weighted total as a cumulative metric:

Following demo implements that approach:

//src array
const soldiers = [
  {name: 'John', shooting: 95, combat: 50, tactic: 88},
  {name: 'Arnold', shooting: 97, combat: 72, tactic: 68},
  {name: 'William', shooting: 87, combat: 86, tactic: 97}
];
//cumulative score
const cumulative = soldier => {
  //weight for each skill
  const weights = {shooting: 1, combat: 1.5, tactic: 1.8};
  //extract skill properties into skills-object
  ({name, ...skills} = soldier);
  //iterate through skills and calculate weighted total
  return Object.entries(skills).reduce((score,item) => score += item[1]*weights[item[0]],0);
};
//best performer
const bestPerformer = soldiers.reduce((best, soldier) => cummulative(best) > cumulative(soldier) ? best : soldier, soldiers[0]);

console.log(bestPerformer);