3

I need to map some user generated fields to something the system I'm working on can recognize.

For this we want to provide a certain amount of freedom for users, and offer five or so options for each of our fields.

So far we have a switch which does the job, but now we have to extend the switch, and it's going to be pretty big. This is needless to say not a very dynamic way of doing it. Is there any alternatives?

function findHeader(object) {
  var title = object.toString().trim().toLowerCase()
  switch (title) {
    case 'name':
    case 'idea':
    case 'ide':
    case 'ide navn':
    case 'title':
    case 'idea name':
      title = 'name'
      break
    case 'beskrivelse':
    case 'problemet':
    case 'description':
    case 'the problem':
    case 'ide beskrivelse':
      title = 'description'
      break
    case 'ejer':
    case 'owner':
    case 'opfinder':
    case 'ide person':
    case 'idea person':
    case 'person':
      title = 'owner'
      break
    case 'duedate':
    case 'deadline':
    case 'tidsfrist':
    case 'sidste dato':
    case 'dato':
    case 'due date':
      title = 'duedate'
      break
    case 'billede':
    case 'billeder':
    case 'image':
    case 'images':
    case 'attachment':
      title = 'imageUrl'
      break
    case "":
      title = 'remove'
      break
    default:
      title = 'Unassigned'
      break
  }
  return title
}
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Anders Jensen
  • 330
  • 3
  • 20
  • please add example for the input also – Naor Tedgi Dec 12 '18 at 10:57
  • How about this? https://stackoverflow.com/questions/35769144/dynamically-adding-cases-to-a-switch – thex Dec 12 '18 at 10:58
  • 2
    You can just create a map. You can store it as a separate JSON file if it is dynamic and big. Personally, Personally for me this "certain amount of freedom" sounds more like ambiguity and confusion. Why would someone want to build a service which allows multiple different names for the same thing and creates a fishy map to handle user's invalid data for him. IMHO :) – Yeldar Kurmangaliyev Dec 12 '18 at 11:00
  • We switched to a system where the label is decoupled from the fieldname. So we offer our users only the fieldname: 'name', 'description' and such, and then let them define any label name they want as tied to the standardized name. So kinda like the opposite of your current method. The big advantage is that you don't need to hard code all the different spellings of the same concept, since the user will ad those themselves to the JSON file / database / data store. – Shilly Dec 12 '18 at 11:16
  • There is a really [good article](https://ultimatecourses.com/blog/deprecating-the-switch-statement-for-object-literals) about it. – Experimenter Apr 19 '22 at 20:39

7 Answers7

6

Perhaps an object?

const titles = {
  'name':        ['name', 'idea', 'ide', 'ide navn', 'title', 'idea name'],
  'description': ['beskrivelse', 'problemet', 'description', 'the problem', 'ide beskrivelse'],
  'owner' :      ['ejer', 'owner', 'opfinder', 'ide person', 'idea person', 'person'],
  'duedate' :    ['duedate', 'deadline', 'tidsfrist', 'sidste dato', 'dato', 'due date'],
  'imageUrl' :   ['billede', 'billeder', 'image', 'images', 'attachment']
}
const getKey = (obj,val) => Object.keys(obj).find(key => obj[key].indexOf(val) !=-1 );

function findHeader(object) {  
  var title = object.toString().trim().toLowerCase();
  return getKey(titles,title) || 'Unassigned' 
}

console.log(
  findHeader("Owner"),
  findHeader("Bla")
)  
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

You can store datas in array of object and search values in it instead of switch

let arr = [
  {
    "title": "name",
    "values": ['idea','ide','ide navn','title','idea name']
  },
  {
    "title": "description",
    "values": ['beskrivelse','problemet','description','the problem','ide beskrivelse']
  },
  {
    "title": "owner",
    "values": ['ejer','owner','opfinder','ide person','idea person','person']
  },
];    

function findHeader(object) {
  let title = object.toString().trim().toLowerCase(),
      res = arr.filter(val => val.values.includes(title));    
  return res.length ? res[0].title : "Unassigned";
}

console.log(findHeader("problemet"));
console.log(findHeader("ide person"));
console.log(findHeader("opfinderrr"));
Mohammad
  • 21,175
  • 15
  • 55
  • 84
1

You can use a regular expression with an object to get the value of an item based on a string of keys:

const titles = {
  "name|idea|ide": "name",
  "beskrivelse|problemt|description|the problem": "description"
};

const get_item = item => titles[Object.keys(titles).find(key => new RegExp(`(\\||^)${item}(\\||$)`).test(key))];

let title = "problemt";
title = get_item(title); // Get the associated value from the key
console.log(title);

See this answer for further details.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
0

The solutions others have posted are great and elegant if one expects not too much data.

If performance is crucial and you have huge dictionaries, and/or a lot of terms to replace (order of magnitude 100k or more pieces of data), then your original solution using switch and case statements will be the best one, especially if you put the assignment line and the break statement after every singe case (making it even uglier). The problem is that you cannot dynamically update that at runtime.

But if dynamic updates is not what you need, you can save this monster of a switch statement into a separate script file as a function, out of sight, keeping your code tidy.

The point is, while the use of JavaScript objects is much more elegant, I wouldn't completely discount the switch & case solution, depending on the application.

Kresimir
  • 777
  • 5
  • 20
0

Cleaner way to do that

if (["name", "idea", "title"].indexOf(title) > -1)
    title= "name"

else if (["description", "detail", "more", "info"].indexOf(title) > -1)
    title = "description"

You can do that for multiple values with the same result

Abraham
  • 12,140
  • 4
  • 56
  • 92
0

One beautiful way of putting a ternary at work is replacing switch case with some clever indenting which looks exactly like a switch statement but in fact much more flexiable;

title = ['name','idea','ide','ide navn','title','idea name'].includes(title)                      ? "name"        :
        ['beskrivelse','problemet','description','the problem','ide beskrivelse'].includes(title) ? "description" :
        ['ejer','owner','opfinder','ide person','idea person','person'].includes(title)           ? "owner"       :
        ['duedate','deadline','tidsfrist','sidste dato','dato','due date'].includes(title)        ? "duedate"     :
        ['billede','billeder','image','images','attachment'].includes(title)                      ? "imageUrl"    :
        title === ""                                                                              ? "remove"      :
                                                                                                    "Unassigned"  ;

You can read the last line as "otherwise".

Redu
  • 25,060
  • 6
  • 56
  • 76
0

I ended up putting my own spin on mplungian's answer. I wrote a more verbose function, but I'm checking to see if the value exists with spaces, underscores, or all smashed together. I probably can and will merge the two functions later.

 function getKey(headerToFind){
      var headers = {
        'FirstName':['first name'],
        'LastName':['last name'],
        'Company':  ['company', 'organization','current company','[ E] Company','company name'],
        'Member_Responded_Datetime__c': ['registration time','date registered','registration date','date'],
        'Email':['email','email address'],
        'City':['city','current city'],
        'PhoneNumber':['phone number'],
        'Country':['country','country/Region','current country'],
        'Title':['job title','title']
    
      }  
    
    
    
      for(var key of Object.keys(headers)){
        for(var x=0;x<headers[key].length;x++){
          var compareValue = headers[key][x];
          var c = headerToFind.toLowerCase();
          if(c == compareValue || c == compareValue.replace(" ","_") || c == compareValue.replace(" ","")){
            return key;
          }
        }//nested for
      }//first for
    
    
    
    }
    function findHeader(header) {  
      return getKey(header) || 'Unassigned';
    }
garek007
  • 395
  • 4
  • 15