Malcolm
Malcolm

Reputation: 891

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

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>

Upvotes: 88

Views: 117600

Answers (13)

Meryan
Meryan

Reputation: 1483

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 ));

Upvotes: 1

vsync
vsync

Reputation: 130431

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

Upvotes: 87

vcz
vcz

Reputation: 11

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

Upvotes: 0

ChickenFeet
ChickenFeet

Reputation: 2813

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.

Upvotes: 4

Neil Stevens
Neil Stevens

Reputation: 3914

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.

Upvotes: 1

Tony JD
Tony JD

Reputation: 11

This is the shortest one.

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

Upvotes: 0

Xotic750
Xotic750

Reputation: 23492

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

Upvotes: 5

Kodie Grantham
Kodie Grantham

Reputation: 2031

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:');
}

Upvotes: 0

Prashobh
Prashobh

Reputation: 9552

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

Upvotes: 1

DMCoding
DMCoding

Reputation: 1237

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
}

Upvotes: 13

quietmint
quietmint

Reputation: 14153

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

Upvotes: 35

Blender
Blender

Reputation: 298392

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();

Upvotes: -2

Ralph
Ralph

Reputation: 407

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.

Upvotes: 30

Related Questions