0

Here is my code:

uniq = function(array) {
    var result = [];
    for (var i = 0; i < array.length; i++) {
        console.log(array[i], " is in ", result, (array[i] in result));
        if (!(array[i] in result)) {
            result.push(array[i]);
        } else {}
    }
    return result;
};

uniq([1, 2, 3, 3, 4, 4]);

Output is:

1 ' is in ' [] false

2 ' is in ' [ 1 ] false

3 ' is in ' [ 1, 2 ] false

3 ' is in ' [ 1, 2, 3 ] false <--- HUH?

4 ' is in ' [ 1, 2, 3, 3 ] false

4 ' is in ' [ 1, 2, 3, 3, 4 ] true <--- now it works correctly

Could someone clue me in please? Why is (!(array[i] in result)) not evaluating to true the first time but is the second time?

Tushar
  • 85,780
  • 21
  • 159
  • 179
lemontree
  • 99
  • 1
  • 7

3 Answers3

4

p in o means "does object o have property named p" (or in case of arrays, equivalently "does array o have an index p"), not "does array o have a value p". [1, 2, 3] has indices 0, 1 and 2 - no 3. [1, 2, 3, 3, 4] has indices from 0 to 4, so 4 is "in".

Use result.indexOf(array[i]) !== -1 as membership test (but be aware that it doesn't work in IE<9 (click "show obsolete browsers"), and you need to do it manually by looping, or use a shim that will do it by looping - i.e. slooooow)

Another approach mentioned in comments is the hashtable approach, but is a bit more restricted.

var uniq = function(array) {
  var result = [];
  var hash = {};
  for (var i = 0; i < array.length; i++) {
    if (!hash[array[i]]) {
      result.push(array[i]);
      hash[array[i]] = true;
    }
  }
  return result;
}

This does not rely on any new features, should work anywhere, and is reasonably fast - it just spends a bit more memory.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • I've actually tried that before but when I did I got an error saying "TypeError: result.indexOf is not a function". – lemontree Jun 02 '15 at 05:32
  • Works for me. What is your browser? (See the edit of my second paragraph). Also, if you limit yourself to things that have nice string representations, you can use a hashtable (JS object) to make it fast even without `indexOf`. – Amadan Jun 02 '15 at 05:34
  • Tried in both Chrome and FF. It does work the JSC command line terminal. Weird. Might have something to do with the larger code this function is in. Thanks – lemontree Jun 02 '15 at 05:39
  • Hmm - the only way this should happen is if someone did something silly like `Array.prototype.indexOf = "stump lemontree"`. Can you `console.log([].indexOf)`? Both in your app's window and in a new window? You should get `function indexOf()` (Google Chrome 43.0.2357.81) – Amadan Jun 02 '15 at 05:41
1

To answer your question,

Why is (!(array[i] in result)) not evaluating to true the first time but is the second time?

The in keyword checks whether the value of array[i] is a key in result or not. It will return true if the key array[i] is present in result

In your example,

1 ' is in ' [] false because result array does not have a key

2 ' is in ' [ 1 ] false because 0 is the only key in result array

3 ' is in ' [ 1, 2 ] false because 0 and 1 is the only key in result array

3 ' is in ' [ 1, 2, 3 ] false because 0, 1 and 2 are the keys in result array

4 ' is in ' [ 1, 2, 3, 3 ] false because 0, 1, 2 and 3 are the keys in result array

4 ' is in ' [ 1, 2, 3, 3, 4 ] true because 0, 1, 2, 3 and 4 are the keys in result array

To achieve your desired result use indexOf function as in the below code

uniq = function(array) {
    var result = [];
    for (var i = 0; i < array.length; i++) {
        console.log(array[i], " is in ", result, (result.indexOf(array[i]) !== -1));
        if (!(array[i] in result)) {
            result.push(array[i]);
        } else {}
    }
    return result;
};
Kira
  • 1,403
  • 1
  • 17
  • 46
0

Use indexOf to check if element exists in array:

The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.

uniq = function(array) {
    var result = [];
    for (var i = 0; i < array.length; i++) {
        if (result.indexOf(array[i]) === -1) {
            result.push(array[i]);
        }
    }
    return result;
};

console.log(uniq([1, 2, 3, 3, 4, 4]));

Demo: https://jsfiddle.net/tusharj/uvzwqw9s/

Docs: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

Tushar
  • 85,780
  • 21
  • 159
  • 179