0

How can I find all items in an array by matching a property and dealing with case insensitivity ONLY IF the values are strings? I have no way to know what data type the property on the object will be. Both the target value and property may be a date, string, number, etc.

I'm basically trying to protect the next developer from shooting himself in the foot:

function getItemsByKey(key, value, isCaseSensitive) {
    var result = [];
    (getAll() || []).forEach(function(item){
        if (!(!!isCaseSensitive)) {
            if (item[key] && item[key].toString().toLowerCase() == value.toString().toLowerCase()) { result.push(item); }
        } else {
            if (item[key] == value) { result.push(item); }
        }
    });
    return result;
}

What happens if they pass in isCaseSensitive = true and the values end up being dates or numbers... or mismatched?

G. Deward
  • 1,542
  • 3
  • 17
  • 30
  • 1
    `if (!(!!isCaseSensitive))` what the... this can be reduced to `if (!isCaseSensitive)` – Tennyson H Feb 23 '16 at 20:58
  • I don't understand what this function is trying to accomplish. Why would you want to add isCaseSensitive to a key retrieval? – VladFr Feb 23 '16 at 20:59
  • Possible duplicate of [How to "instanceof" a primitive string (string literal) in JavaScript](http://stackoverflow.com/questions/16792051/how-to-instanceof-a-primitive-string-string-literal-in-javascript) – BatScream Feb 23 '16 at 21:00
  • Anyway, you can check if value is a string using typeof: http://stackoverflow.com/questions/4059147/check-if-a-variable-is-a-string – VladFr Feb 23 '16 at 21:00
  • Are you trying to find items in an array, e.g. `['value1', 'value2']` or an object, e.g. `{ 'value1': 'hello', 'value2': 'hi' }`? – Tennyson H Feb 23 '16 at 21:01
  • @VladFr : There is now way to know what type of objects `getAll()` will return. It is meant to be a helper / utility function on a cache. – G. Deward Feb 23 '16 at 21:01
  • @VladFr : I'm trying to return all objects where a certain property might be matched. For example `fruit == 'apple'` or 'count == 42`. – G. Deward Feb 23 '16 at 21:02
  • Regardless of the solution to this problem, it's highly recommended to use strong-typed comparison in js (`===` instead of `==`)... – Jan Chimiak Feb 23 '16 at 21:03
  • @JanChimiak : I won't have any way to know what type of objects will be returned by `getAll()` nor if the target property will be the expected type. The goal of using `toString()` was to reduce the properties to a common type. – G. Deward Feb 23 '16 at 21:06
  • I've posted the complete service on CodeReview: http://codereview.stackexchange.com/questions/120914/member-specific-object-cache-for-angular – G. Deward Feb 23 '16 at 21:36

1 Answers1

2

See inline comment.

function getItemsByKey(key, value, isCaseSensitive) {
    var result = [];
    (getAll() || []).forEach(function(item){
        // Either the values are equal OR (not case sensitive AND item[key] and value are strings AND non-case sensitive match)
        if (item[key] == value || (
          !isCaseSensitive &&
          typeof item[key] == 'string' &&
          typeof value == 'string' &&
          item[key].toLowerCase() == value.toLowerCase())
        ) {
            result.push(item);
        }
    });
    return result;
}
arcyqwerty
  • 10,325
  • 4
  • 47
  • 84
  • Makes sense. Thanks. – G. Deward Feb 23 '16 at 21:11
  • What would happen if one value was a number and the other a string? Or one a date and the other a number? Could they still be compared? – G. Deward Feb 23 '16 at 21:19
  • I've posted the complete service on CodeReview: http://codereview.stackexchange.com/questions/120914/member-specific-object-cache-for-angular – G. Deward Feb 23 '16 at 21:36
  • In this case, I forced both to be strings. If you want to use JS type coercion for equality (see [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Using_the_Equality_Operators)) then you could say `(typeof item[key] == 'string' || typeof value == 'string)` which only requires one of the compared values to be a string. – arcyqwerty Feb 23 '16 at 23:30
  • 1
    You can also compare `item[key].toString().toLowerCase() == value.toString().toLowerCase()` like you have in your question. You may want to use `"" + arg` instead of `toString()` to get around corner cases like `undefined` or primitives (i.e. `1` as opposed to `Number(1)` although this won't come up in a function invocation). – arcyqwerty Feb 23 '16 at 23:30