Home > Mobile >  Mapping over array of objects and picking out values from unknown keys
Mapping over array of objects and picking out values from unknown keys

Time:11-30

Tallying which color has a greater value in each array element for data. Then push the higher valued color into an empty object, and/or increment that color by 1. Lastly sort the totals object highest to lowest in terms of the totals property values and return highest valued color

Struggling with how to map over this structure array since property keys are not uniform. Should I destructure it?

*I can redesign data structure as needed, and if it's easier to solve with a different design, please let me know!

data = [
   { orange: 4, green: 4},
   { green: 0, yellow: 0},
   { yellow: 1, orange: 4 },
   { blue: 2, green: 1 }, 
   { blue: 2, yellow: 1 }, 
   { green: 3, yellow: 2 },
   { green: 1, blue: 3},
   { green: 5, yellow: 2 }, 
 ]
```

```
totals = {
  blue: 3,
  green: 2,
  orange: 1,
}

```
solution: 
```
highValueColor = blue
```


// PSEUDOCODE
  //map over the array => data.map()
  //identify highest value between two elements => propA - propB
  //check to see if the color's (key) in the element has already been added to totals object 
  //IF the key does not yet exist, create a property in the tally object with the color(key) and set its value to 1
  //IF the key is already listed in tally object, increment its property value by 1 =>   
  //sort totals object => Math.max()
  //return highest value color
`

CodePudding user response:

You're in luck as you are using JS!

It's super easy (or loosey-goosey, depending on your personal preference) to set/get data inside of JS objects using their keys using the { [someVariable]: value } notation. You can also check for existence of a key inside of an object using the in operator, like so:

const obj = { red: 'foo' };
const red = 'red';
console.log(red in obj) // true
console.log('red' in obj) // true
console.log(blue in obj) // false

So, combining that with a couple simple loops we can get this:

const data = [
   { orange: 4, green: 4},
   { green: 0, yellow: 0},
   { yellow: 1, orange: 4 },
   { blue: 2, green: 1 }, 
   { blue: 2, yellow: 1 }, 
   { green: 3, yellow: 2 },
   { green: 1, blue: 3},
   { green: 5, yellow: 2 }, 
 ];
 
const totals =  {};

for (const colors of data) {
    const [color1, color2] = Object.keys(colors);
    let color = color1;
    if (colors[color1] < colors[color2]) {
        color = color2
    }
    totals[color] = totals[color] ? totals[color]   1 : 1;
}

console.log(totals) // { orange: 2, green: 3, blue: 3 }

This isn't a performant solution by any means, but it is mainly held back by the structure of your data and needing to iterate over every value in order to check each key and its corresponding value.

Objects are very powerful in JS and form the basis of its flexibility. You may be able to leverage this to get a faster solution if you are eventually held back by performance issues depending on the size of the dataset.

CodePudding user response:

Not sure how much help this is, @hopzebordah answer seems fine except that it looks like it counts a colour when both colours have the same value. (e.g. { orange: 4, green: 4} gets counted as orange).

I added a version with map in the comments as you seemed to be interested in that, but I might have misunderstood what you were trying to achieve.

If you don't need the sorted object and only the highest value, then you probably don't need to sort the object first. Hopefully highest_value_unsort demonstrates this.

const data = [
  { orange: 4, green: 4},
  { green: 0, yellow: 0},
  { yellow: 1, orange: 4 },
  { blue: 2, green: 1 }, 
  { blue: 2, yellow: 1 }, 
  { green: 3, yellow: 2 },
  { green: 1, blue: 3},
  { green: 5, yellow: 2 }, 
];

const pick_color = (color_obj) => {
  const [[color1, val1], [color2, val2]] = Object.entries(color_obj);
  
  return val1 === val2 ?
    null :
    val1 > val2 ?
        color1 :
        color2;
};


const unsorted = {};
for(const color_obj of data) {
  const color = pick_color(color_obj);
  
  if(color) {
    unsorted[color] = (unsorted[color] ?? 0)   1;
  }
}

// version of the above using reduce:
// const unsorted = data.reduce((acc, val) => {
//   const color = pick_color(val);
//   
//   return !color ?
//     acc :
//     { ...acc, [color]: (acc[color] ?? 0)   1 };
// }, {});

// version of the above using map then reduce:
// const unsorted = data
//   .map(pick_color)
//   .reduce(
//     (acc, color) => !color ?
//       acc :
//       { ...acc, [color]: (acc[color] ?? 0)   1 },
//     {}
//   );

const sorted = Object.fromEntries(
  Object.entries(unsorted)
    .sort(([, a_val], [, b_val]) => b_val - a_val)
);

const highest_value = Object.entries(sorted)[0][0];
const highest_value_unsort = Object.entries(unsorted)
  .reduce(
    (acc, entry) => entry[1] > acc[1] ? entry : acc,
    ['none', 0]
  )[0];

console.log(sorted);
console.log(highest_value);
console.log(highest_value_unsort);

Some reference links in case you're not familiar with some of the features used above:

  • Related