简体   繁体   中英

How to return a string based on correspondent values summed from an array of strings

As the topic states what is the best way to make it so that when you pass an array of emotions/values, to show the closest value based on a numeric mapping in javascript?.

Assume that 'Glad' is the same thing as 'Happy', and 'Down' is the same thing as 'Sad'. Ithe code I've tried seems incredibly lengthy and gets bloated if I add more emotions/states (ie Angry). Aside from the emotions array, any new functions and data structures and variables can be changed/introduced.

for example, I can get a list of emotions:

let emotions = ['Happy','Happy','Sad','Glad','Angry']; 

Now I want to return a string that reflects what the 'closest' emotion based on these 5 emotions.

For a better example, let's assume the values correspondent to each emotion is:

Angry = 1, Happy = 2, Sad = 3

I was trying something like:

var numb = 0;
for (var i = 0; i < emotions.length; i++) {
  if (numb == 'Angry')
    numb += 1;
  if (numb == 'Happy' || numb == 'Glad')
    numb += 2;
  if (numb == 'Sad' || numb == 'Down')
    numb += 3;
}
var average = numb / emotions.length;

// check which number is closer to
if (average < 1.5)
  return 'Angry';
if (average >= 1.5 && < 2.5)
  return 'Happy';
if (average > 2.5)
  return 'Sad';
if (average == 1.5)
  return 'Angry or Happy';
if (average == 2.5)
  return 'Happy or Sad';

My expected result based on this list of emotions is:
2(*Happy*) + 2(*Happy*) + 3(*Sad*) + 2(*Happy|Glad*) + 1(*Angry*) = 10
Then divide by 5 (the emotions array length), resulting in 2.
So the result that should be returned, as string, is "Happy" .

Let's say I added a fourth type of emotion/feeling... I would be adding more and more of these conditions, and it gets more complicated in the logic checking for the ranges of the numbers.

I am looking at the list of emotions as a whole, and trying to come up with an overall emotion that represents the whole list.

What is the best way to do this so that the code looks clean and I can support more states without having the lines of code become too long?

What about something like this:

Having two object constants:
emotionsValues : Here you assing a value to each emotion you want, like a score to each.
emotionsRank : Here is the final result of each value, based on average you'll get the result from here.

Now:

  1. Receive the emotions array by parameter.

  2. reduce it based on the value of each mapped emotion (using emotionsValues ).

  3. Get the average

  4. See if the floor value + ceil value divided by 2 is equal to the number itself (it means its exactly the half), so use the "emotion or emotion".

  5. OR, if not the half, then round to the nearest and get the correct emotion. Don't forget to check if average is below 1 or bigger the the last rank (3 in this case)

 const emotionsValues = { "Angry": 1, "Happy": 2, "Glad": 2, "Sad": 3, "Down": 3, } const emotionsRank = { 1: "Angry", 2: "Happy", 3: "Sad", } function getEmotion(arrayEmot) { let numb = arrayEmot.reduce((acc, v) => Number(emotionsValues[v]) + acc, 0); let avg = numb / arrayEmot.length; let min = Math.floor(avg) let max = Math.ceil(avg) if ((min + max) / 2 == avg && min != max) { return emotionsRank[min] + " or " + emotionsRank[max] } else { let rounded = avg < 1 ? 1 : avg > 3 ? 3 : Math.round(avg); return emotionsRank[rounded]; } } let emotionsTest = ['Happy', 'Happy', 'Sad', 'Glad', 'Angry']; console.log(getEmotion(emotionsTest)) let emotionsTest2 = ['Happy', 'Happy', 'Sad', 'Sad']; console.log(getEmotion(emotionsTest2))

  • You may create the function emo to value and its reciprocal one: value to emotionS:
  • Then you map every emotions found in array to its value
  • do your standard mathematical stuff
  • and get back to emotions via the reciprocal function

 const emoToValue = { Glad: 1, Happy: 1, Sad: 2 } const valueToEmos = Object.entries(emoToValue).reduce((acc, [emo, val]) => { acc[val] = acc[val] || [] acc[val].push(emo) return acc }, {}) //compute the average: function avgEmotion (emotions) { if (emotions.length == 0) return '' const avg = emotions.reduce((s, em) => s + emoToValue[em], 0) / emotions.length return valueToEmos[Math.round(avg)].join(' or ') } console.log('str', avgEmotion(['Happy', 'Happy', 'Sad', 'Happy'])) //Glad or Happy console.log('str', avgEmotion(['Happy', 'Happy', 'Sad', 'Sad'])) //Sad

You could create a set of indices and get the values by filtering with the index.

 function getEmotion(emotions, value) { var values = new Set([value + 0.5, value - 0.5, Math.round(value)]); return emotions.filter((e, i) => values.has(i + 1)).join(' and '); } console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1)); console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1.5)); console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1.7));

This function explicitly checks for the "mid" case and also for out of range values (since it's based on indices):

function getEmotion(emotions, value) {

  // Out of range
  if ( value > emotions.length ) return emotions[emotions.length - 1];
  if ( value < 1 ) return emotions[0];

  // Determine if decimal is .5
  let mid = value % 1 === .5;
  // Round the value to the nearest integer
  let rounded = Math.round(value);

  return mid ? `${emotions[rounded - 2]} or ${emotions[rounded - 1]}` : emotions[rounded - 1];

}

Output:

let emotions = ['Happy', 'Happy', 'Sad', 'Glad', 'Angry'];

console.log(getEmotion(emotions, -23));    // Happy
console.log(getEmotion(emotions, 0));      // Happy
console.log(getEmotion(emotions, 1));      // Happy
console.log(getEmotion(emotions, 2.43));   // Happy
console.log(getEmotion(emotions, 2.5));    // Happy or Sad
console.log(getEmotion(emotions, 3.1));    // Sad
console.log(getEmotion(emotions, 155.65)); // Angry

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM