2
\$\begingroup\$

Could anyone help me with below logic implementation. I am new to Javascript and have been practicing advanced functions. The below code does the job but is there a better way to achieve the same? I want to make my code perfect.

I am grouping by location and then getting the sentiments count.

// Feedback
const sentiments = [
  { location: "France", sentiment: "dissatisfied" },
  { location: "France", sentiment: "happy" },
  { location: "France", sentiment: "happy" },
  { location: "Germany", sentiment: "happy" },
  { location: "France", sentiment: "sad" },
  { location: "Germany", sentiment: "sad" },
  { location: "Germany", sentiment: "happy" },
  { location: "Germany", sentiment: "happy" },
  { location: "Germany", sentiment: "sad" },
  { location: "Germany", sentiment: "dissatisfied" },
  { location: "Spain", sentiment: "dissatisfied" },
  { location: "Spain", sentiment: "happy" },
  { location: "Spain", sentiment: "happy" },
];


// Group by Sentiments
function GroupBySentiments(location, acc, cvalue) {
  let key = cvalue["sentiment"];
  // first time 0th index will be empty, so insert the sentiment
  if (acc[location][0] == undefined) {
    acc[location].push({ [key]: 1 });
  } else if (acc[location].findIndex((l) => l.hasOwnProperty(key)) == -1) {
    acc[location].push({ [key]: 1 });
  } else {
    let index = acc[location].findIndex((l) => l.hasOwnProperty(key));
    acc[location][index][key] += 1;
  }
  return acc;
}

//Group by location
result = sentiments.reduce((acc, sentiment) => {
  let key = sentiment["location"];
  if (!acc[key]) {
    acc[key] = [];
  }
  return GroupBySentiments(key, acc, sentiment);
}, {});

//OUTPUT
{
  France: [ { dissatisfied: 1 }, { happy: 2 }, { sad: 1 } ],
  Germany: [ { happy: 3 }, { sad: 2 }, { dissatisfied: 1 } ],
  Spain: [ { dissatisfied: 1 }, { happy: 2 } ]
}

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Review! Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Commented Jun 5, 2021 at 11:13

1 Answer 1

3
\$\begingroup\$

Output format

For each location, you have a list of objects with a single sentiment.

i.e.: { France: [ { dissatisfied: 1 }, { happy: 2 }, ... ] }

To access how many are "happy" from France you would need to do something like

const happySentiment = results.France.find((sentiment) => sentiment.hasOwnProperty("happy"));
const happyCount = happySentiment ? happySentiment.happy : 0; 

This is, imo, a lot of work just to find how many people are happy in France, at this point you might as well add +1 to dissatisfied for me.

Joke aside, if there is not a specific reason to work with that output format, why not generate something that is easier to handle?

i.e.: { France: { dissatisfied: 1, happy: 2 }}

and thus to access the same result as before would be:

const happyCount = results.France.happy ?? 0;

New Implementation

const sentiments = [
  { location: "France", sentiment: "dissatisfied" },
  { location: "France", sentiment: "happy" },
  { location: "France", sentiment: "happy" },
  { location: "Germany", sentiment: "happy" },
  { location: "France", sentiment: "sad" },
  { location: "Germany", sentiment: "sad" },
  { location: "Germany", sentiment: "happy" },
  { location: "Germany", sentiment: "happy" },
  { location: "Germany", sentiment: "sad" },
  { location: "Germany", sentiment: "dissatisfied" },
  { location: "Spain", sentiment: "dissatisfied" },
  { location: "Spain", sentiment: "happy" },
  { location: "Spain", sentiment: "happy" },
];

const result = sentiments.reduce((acc, {location, sentiment}) => {
  const sentimentCounts = acc[location] ?? {};
  sentimentCounts[sentiment] = (sentimentCounts[sentiment] ?? 0) + 1;
  acc[location] = sentimentCounts;
  return acc;
}, {});

console.log(result);

\$\endgroup\$
2
  • \$\begingroup\$ I appreciate this, Very nice solution! many thanks \$\endgroup\$ Commented Jun 5, 2021 at 14:06
  • \$\begingroup\$ One option depending on your needs is just counting in the original array (loc, sent) => sentiments.filter(s => s.location == loc && s.sentiment == sent).length. Considered making this an answer, but it's more of a "for completeness" addition \$\endgroup\$
    – JollyJoker
    Commented Jun 5, 2021 at 14:24

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.