0

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
`

2 Answers 2

1

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:

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for clarifying the necessity (or lack thereof) of sorting. I wondered if I was including extra steps, and I was! And you perfectly understood my pull toward using map() for a solution. I appreciate how you demo'd both reduce() and map(). Also, I was trying to sort out why hopzedah's solution was returning 1 too many for green and orange. I deeply appreciate your input! I now need to write a function in the case of equally valued colors. I may need your assistance again soon enough. Do you think I should start a new query or edit the question above?
I really don't know what the proper advice would be for the edit vs new question but my guess would be that if you're clarifying your original intent behind this question then you would edit it otherwise create a new question. If people start adjusting the questions away from what they were originally asking it can mean answers become obsolete.
0

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.

6 Comments

Many, many thanks @hopzebordah. If the dataset was much, much bigger and I'd want a far more performant solution, how would you design the structure of the data?
@barleyhorse Depends on where that inital dataset is coming from... if you have total control over it, you can avoid the nested loops by making that existence check/setting each count of the color's occurrence as you create the data instead of performing it after, if that makes sense. Like doing both at the same time since it's a pretty simple check
the data set is delivered by the client but they can them format it in any way I like. What would you suggest?
@barleyhorse I just updated the code in the answer as I misunderstood your original question, my apologies. As for performance, it really hinges on whether your client can flatten the structure of that array. Honestly, as long as there is a guarantee that there will only ever by 2 elements in each sub object then there shouldn't be a huge performance issue... but if it does cause problems, then it would be best to start with flattening that dataset if possible
I'm grateful for your help! There will ONLY EVER be two colors in each sub object, so I'll stop worrying about the data design. Your current code is coming back with a reference error that 'colors' is not defined. How should it be defined? Your earlier version did so in the second for loop (' for ( color in colorObject) { ')
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.