How do I make Array.indexOf() case insensitive?

Javascript

Javascript Problem Overview


I am making a piece of code for a website that will have a list of names in an array and pick a random name, I want to add a feature that will let the user add or delete a name from the array. I have all of these features but when deleting a name, the user has to type the name to match the Case in the array. I tried to make the so it would be Case-Insensitive, what am I doing wrong?

<html>
<!--Other code uneeded for this question-->
<p id="canidates"></p>
<body>
<input type="text" id="delname" /><button onclick="delName()">Remove Name from List</button>
<script>

//Array of names

var names = [];

//Other code uneeded for this question

//List of Canidates
document.getElementById('canidates').innerHTML = 
"<strong>List of Canidates:</strong> " + names.join(" | ");

//Other code uneeded for this question

//Remove name from Array

function delName() {
    var dnameVal = document.getElementById('delname').value;
    var pos = names.indexOf(dnameVal);
    var namepos = names[pos]
    var posstr = namepos.toUpperCase();
    var dup = dnameVal.toUpperCase();
    if(dup != posstr) {
		alert("Not a valid name");
		}
    else {
        names.splice(pos, 1);
        document.getElementById('canidates').innerHTML = 
        "<strong>List of Canidates:</strong> " + names.join(" | ");
	    }
    }	
</script>
</body>
</html>

Javascript Solutions


Solution 1 - Javascript

ES2015 findIndex:

var array = ['I', 'hAve', 'theSe', 'ITEMs'],
    indexOf = (arr, q) => arr.findIndex(item => q.toLowerCase() === item.toLowerCase());

console.log(  indexOf(array, 'i')      ) // 0
console.log(  indexOf(array, 'these')  ) // 2
console.log(  indexOf(array, 'items')  ) // 3

Solution 2 - Javascript

In ECMA-262, 5th edition, you could use Array.prototype.some for this.

var array = [ 'I', 'hAve', 'theSe', 'ITEMs' ];
var query = 'these'.toLowerCase();
var index = -1;
array.some(function(element, i) {
    if (query === element.toLowerCase()) {
        index = i;
        return true;
    }
});
// Result: index = 2

Solution 3 - Javascript

Easy way would be to have a temporary array that contains all the names in uppercase. Then you can compare the user input. So your code could become somthing like this:

function delName() {
    var dnameVal = document.getElementById('delname').value;
    var upperCaseNames = names.map(function(value) {
      return value.toUpperCase();
    });
    var pos = upperCaseNames.indexOf(dnameVal.toUpperCase());
    
    if(pos === -1) {
        alert("Not a valid name");
        }
    else {
        names.splice(pos, 1);
        document.getElementById('canidates').innerHTML = 
        "<strong>List of Canidates:</strong> " + names.join(" | ");
        }
    }

Hope this helps solve your problem.

Solution 4 - Javascript

The most elegant solution would be to convert the array into a string first, then do a case insensitive comparison. For example:

var needle = "PearS"
var haystack = ["Apple", "banNnas", "pEArs"];
var stricmp = haystack.toString().toLowerCase(); // returns 
                                   // "apple,bananas,pears"
if (stricmp.indexOf(needle.toLowerCase()) > -1) {
    // the search term was found in the array
} else {
    // the search term was not found in the array
}

Solution 5 - Javascript

Probably best to create your own custom indexOf method, something like this.

'use strict';

var customIndexOf = function(arrayLike, searchElement) {
  var object = Object(arrayLike);
  var length = object.length >>> 0;
  var fromIndex = arguments.length > 2 ? arguments[2] >> 0 : 0;
  if (length < 1 || typeof searchElement !== 'string' || fromIndex >= length) {
    return -1;
  }

  if (fromIndex < 0) {
    fromIndex = Math.max(length - Math.abs(fromIndex), 0);
  }

  var search = searchElement.toLowerCase();
  for (var index = fromIndex; index < length; index += 1) {
    if (index in object) {
      var item = object[index];
      if (typeof item === 'string' && search === item.toLowerCase()) {
        return index;
      }
    }
  }

  return -1;
};

var names = [
  'John',
  'Anne',
  'Brian'
];

console.log(customIndexOf(names, 'aNnE'));

Or even

'use strict';

var customIndexOf = function(array, searchElement, fromIndex) {
  return array.map(function(value) {
    return value.toLowerCase();
  }).indexOf(searchElement.toLowerCase(), fromIndex);
};

var names = [
  'John',
  'Anne',
  'Brian'
];

console.log(customIndexOf(names, 'aNnE'));

You may also want to add more checks to be sure that each element in the array is actually a String and that the searchElement is also actually a String too. If pre-ES5 then load appropriate shims

Solution 6 - Javascript

You can use Array.prototype.find()
found = myArray.find(key => key.toUpperCase() === searchString.toUpperCase()) != undefined;

Example:

myArray = ['An', 'aRRay', 'oF', 'StringS'];
searchString = 'array';
found = myArray.find(key => key.toUpperCase() === searchString.toUpperCase()) != undefined;
if (found ) {
    // The array contains the search string
}
else {
    // Search string not found
}

Note: Array cannot contain undefined as a value.

Solution 7 - Javascript

It is possible using by map method. For example see below code

var _name = ['prasho','abraham','sam','anna']
var _list = [{name:'prasho'},{name:'Gorge'}];

for(var i=0;i<_list.length;i++)
{
   if(_name.map(function (c) {
     return c.toLowerCase();
   }).indexOf(_list[i].name.toLowerCase()) != -1) { 
  //do what ever
   }else{
     //do what ever
   }
}

More info

Solution 8 - Javascript

I needed something similar to this where I needed compare two strings using includes and needed to be able to support both case and case insensitive searches so I wrote the following small function

function compare(l1: string, l2: string, ignoreCase = true): boolean {
  return (ignoreCase ? l1.toLowerCase() : l1).includes((ignoreCase ? l2.toLowerCase() : l2));
}

Same principle could apply to indexOf as below

function indexOf(l1: string, l2: string, ignoreCase = true): number {
  return (ignoreCase ? l1.toLowerCase() : l1).indexOf((ignoreCase ? l2.toLowerCase() : l2));
}

I know this is not specifically Array.indexOf but hope this helps someone out if the come across this post on their travels.

To answer the ops question though, you can apply this similarly to an array combined with this answer from @ULIT JAIDEE (the slight change to this was using the tilda character as a separator in case any of the array values contained spaces)

function compare(l1: any[], l2: any[], ignoreCase = true): boolean {
  return (ignoreCase ? l1.join('~').toLowerCase().split('~') : l1).indexOf((ignoreCase ? l2.join('~').toLowerCase().split('~') : l2));
}

Again hope this helps.

Solution 9 - Javascript

Turn the array into a string separated by a delimiter, turn that string lowercase, and then split the string back into an array by the same delimiter:

function findIt(arr, find, del) {
  if (!del) { del = '_//_'; }
  arr = arr.join(del).toLowerCase().split(del);
  return arr.indexOf(find.toLowerCase());
}

var arr = ['Tom Riddle', 'Ron Weasley', 'Harry Potter', 'Hermione Granger'];
var find = 'HaRrY PoTtEr';
var index = findIt(arr, find);

if (~index) {
  alert('Found ' + arr[index] + '! :D');
} else {
  alert('Did not find it. D:');
}

Solution 10 - Javascript

This is the shortest one.

haystack.join(' ').toLowerCase().split(' ').indexOf(needle.toLowerCase())

Solution 11 - Javascript

// unique only, removes latter occurrences    
array.filter((v, i, a) => a.findIndex(j => v.toLowerCase() === j.toLowerCase()) === i);

Solution 12 - Javascript

To improve on @vsync answer and handle mixed content in the array here is my take. (I understand the OP is about case-sensitive thus it implies strings, maybe :)

var array = ['I', 'hAve', 7, {}, 'theSe', 'ITEMs'],
  Contains = (arr, q) =>
    arr.findIndex((item) => q.toString().toLowerCase() === item.toString().toLowerCase());

console.log(Contains(array, 'i'));
console.log(Contains(array, 'x'));
console.log(Contains(array, {} ));
console.log(Contains(array, 7 ));

Solution 13 - Javascript

You can't make it case-insensitive. I'd use an object instead to hold a set of names:

function Names() {
	this.names = {};

	this.getKey = function(name) {
		return name.toLowerCase();
	}

	this.add = function(name) {
		this.names[this.getKey(name)] = name;
	}

	this.remove = function(name) {
		var key = this.getKey(name);

		if (key in this.names) {
			delete this.names[key];
		} else {
			throw Error('Name does not exist');
		}
	}

	this.toString = function() {
		var names = [];

		for (var key in this.names) {
			names.push(this.names[key]);
		}

		return names.join(' | ');
	}
}

var names = new Names();

function update() {
	document.getElementById('canidates').innerHTML = '<strong>List of Canidates:</strong> ' + names;
}

function deleteName() {
	var name = document.getElementById('delname').value;

	try {
		names.remove(name);
		update();
	} catch {
		alert('Not a valid name');
	}
}

update();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMalcolmView Question on Stackoverflow
Solution 1 - JavascriptvsyncView Answer on Stackoverflow
Solution 2 - JavascriptquietmintView Answer on Stackoverflow
Solution 3 - JavascriptRalphView Answer on Stackoverflow
Solution 4 - JavascriptDMCodingView Answer on Stackoverflow
Solution 5 - JavascriptXotic750View Answer on Stackoverflow
Solution 6 - JavascriptChickenFeetView Answer on Stackoverflow
Solution 7 - JavascriptPrashobhView Answer on Stackoverflow
Solution 8 - JavascriptNeil StevensView Answer on Stackoverflow
Solution 9 - JavascriptKodie GranthamView Answer on Stackoverflow
Solution 10 - JavascriptULIT JAIDEEView Answer on Stackoverflow
Solution 11 - JavascriptvczView Answer on Stackoverflow
Solution 12 - JavascriptMeryanView Answer on Stackoverflow
Solution 13 - JavascriptBlenderView Answer on Stackoverflow