3

I have to find first duplicate value in array and then return its index in variable firstIndex. This has to be done with for loop which should stop after having found first duplicate. I know this is probably pretty simple but I got stuck. So far I have this but it doesn't seem to be working:

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 0; a < numbers4.length; a++) {
    for (var b = a+1; b < numbers4.length; b++) {
        if (numbers4[a] === numbers4[b])
            firstIndex = numbers4.indexOf(numbers4[a]);
            break;
    }
}
console.log(firstIndex);

Console prints out 1 which is fine because 2 is first duplicate, but when I change numbers in array, the loop doesn't work. Can you advise what can be changed here?

Thanks in advance!

Joanna
  • 289
  • 1
  • 6
  • 16

9 Answers9

7

If I correctly understand your question, that's should help you... Basically, you need for a double iteration.

const firstDupeIndex = list => list.findIndex(
  (item, index) => list.lastIndexOf(item) !== index
);

console.log(
  "First Dupe at index:", 
  firstDupeIndex([5, 2, 3, 4, 4, 6, 7, 1, 2, 3])
);

Thee above implementation comes with the drawback of being O(n2), due to nesting the lastIndexOf within the findIndex function.

A better solution would be to index your occurrences by building a dictionary, therefore keeping time complexity to just O(n) in the worst case. Probably a little bit less neat, but surely more efficient with big inputs.

const firstDupeIndex = (list) => {
  const dict = {};
  
  for (const [index, value] of list.entries()) {
    if (dict.hasOwnProperty(value)) {
      return dict[value];
    }
  
    dict[value] = index;
  }
  
  return -1;
};

console.log(
  "First Dupe at index:", 
  firstDupeIndex(['a', 'b', 'c', 'd', 'e', 'b', 'z', 't', 'c'])
);
Hitmands
  • 13,491
  • 4
  • 34
  • 69
3

Change your code with the following

    var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
    var firstIndex = "";
   var isMatch=false;
    for (var a = 0; a < numbers4.length; a++) {
        for (var b = a+1; b < numbers4.length; b++) {
            if (numbers4[a] === numbers4[b]){
                firstIndex = numbers4.indexOf(numbers4[a]);
                isMatch=true;
                break;
          }
        }
           if (isMatch) {break;}
    }
    console.log(firstIndex);
Amy
  • 4,034
  • 1
  • 20
  • 34
  • 1
    you would need one more break inside of the top level for loop. The internal break will only break the inner for loop, the external for loop is still not broken – Sachin Nayak Sep 06 '16 at 10:10
  • @SachinNayak thank you for suggestion i have updated my answer. – Amy Sep 06 '16 at 10:13
1

I would use an object remembering the values already found... Something like that should work ;)

var numbers4 = [5, 2, 3, 4, 4, 6, 7, 1, 2, 3];

function findFirstDuplicateIndex(arr){
  var found = {};
  
  for (var a = 0, aa = arr.length; a < aa ; a++) {
    if (found[arr[a]])
      return found[arr[a]];
  
    found[numbers4[a]] = a
  }
}

console.log(findFirstDuplicateIndex(numbers4));

It's quite fast because you just loop one time through the array. The rest of the time you just access an object property or you set the object property... Let me know if you have questions ;)

However maybe there something faster... It's just an idea ^^

PS: It also works with words, not just numbers

R. Foubert
  • 633
  • 4
  • 8
  • You're snippet returns `3` while first duplicate has index `4` actually. – Jakub Matczak Sep 06 '16 at 10:12
  • I think he wants the index of the first occurence of the duplicated number... He said "Console prints out 1 which is fine because 2 is first duplicate". If he wants the duplicated number index, he just has to return a instead of found[arr[a]] – R. Foubert Sep 06 '16 at 10:14
  • Uhm.. it seems you're right. Anyway, you don't need to store `found` as you can simply use `indexOf` or even `lastIndexOf` as I did in my answer. – Jakub Matczak Sep 06 '16 at 10:17
  • Yes you're right indexOf would work. You will just have to check if the current index is different of arr.indexOf(arr[a]) and it would work ! However I think it would be slower than accessing an object property... Especially on big arrays. I'm not sure about this but I think my solution is faster. What do you think ? – R. Foubert Sep 06 '16 at 10:23
  • I was just about to compare them but I've noticed that the correct returned value should be `1` as the value of `2` is first one that is duplicated. You're script returns `3` – Jakub Matczak Sep 06 '16 at 10:29
  • I changed the input array ;) My duplicated value is 4 instead of 2 – R. Foubert Sep 06 '16 at 11:20
  • There's one more `2` (with index `8`) so still the `2` is the first duplicate. – Jakub Matczak Sep 06 '16 at 11:25
  • Yes but the 4 is the first to be duplicated when you go through the array... It depends on what you understand... However, maybe i'm wrong – R. Foubert Sep 06 '16 at 12:28
  • Yeah.. it always depends... :) – Jakub Matczak Sep 06 '16 at 12:31
0

You don't even need nested for loops.

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 1; a < numbers4.length; a++) { //start from second elem since first is never a duplicate
        if (numbers4.lastIndexOf(numbers4[a])> a) {
            firstIndex = a;
            break;
        }
}
console.log(firstIndex); //1

All you have to do during iterating is to check if current value exists somewhere further in array. That is done by checking last index of this value's occurrence using lastIndexOf().

Jakub Matczak
  • 15,341
  • 5
  • 46
  • 64
0

Your problem is - you have two loops and only one break, you need to break out of both.

Why not simply return the index as soon as values match?

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
function getDuplicate(numbers4)
{
    for (var a = 0; a < numbers4.length; a++) {
        for (var b = a+1; b < numbers4.length; b++) {
            if (numbers4[a] === numbers4[b]){
                return a;
            }
        }
    }
}
console.log(getDuplicate(numbers4 ));

However, you can optimize your code further by keeping a map

function getDuplicate( numbers )
{
    var map = {};
    for (var a = 0; a < numbers.length; a++) 
    {
        if( map[ numbers[ a ] ] )
        {
          return a;
        }
        map[ numbers[ a ] ] = true;
    }
    return -1;
}
gurvinder372
  • 66,980
  • 10
  • 72
  • 94
0

You can check if indexOf() is not equal to lastIndexOf() and return value and break loop

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var i = 0; i < numbers4.length; i++) {
  if (numbers4.indexOf(numbers4[i]) != numbers4.lastIndexOf(numbers4[i])) {
    firstIndex = i;
    break;
  }
}

console.log(firstIndex)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • Since current index is first for this value (because you would break the loop earlier otherwise) then `indexOf` is unnecessary here. It can be done simply by `i < numbers4.lastIndexOf(numbers4[i])` as I did in my answer. – Jakub Matczak Sep 06 '16 at 10:23
  • This one looks simpler than mine, I checked and it works properly. Thanks! – Joanna Sep 06 '16 at 11:23
0

Your break; terminates b loop, because if() is not using parenthesis {}.

Additionally, firstIndex should be simply set to either a or b depending on whether you need to return the duplicate's first occurance or first repetition.

It should be:

if (numbers4[a] === numbers4[b])
{
            firstIndex = a;
            break;
}
Gnudiff
  • 4,297
  • 1
  • 24
  • 25
0

var numbers = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex;
var len = numbers.length;

for (var i = 0; i < len; i++) {
  var tmpArray = numbers.slice(i + 1, len);
  var index = tmpArray.indexOf(numbers[i]);
  if (index !== -1) {
    firstIndex = index + i + 1;
    break;
  }
}
console.log(firstIndex);

Update:

Actually your logic is right, but you missed braces for if condition and also if the condition satisfies then it means firstIndex is the same as a

This is your code with braces,

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 0; a < numbers4.length; a++) {
  for (var b = a + 1; b < numbers4.length; b++) {
    if (numbers4[a] === numbers4[b]) {
      firstIndex = a
      break;
    }
  }
}
console.log(firstIndex);
Flying Gambit
  • 1,238
  • 1
  • 15
  • 32
0

The question states the first dupe in the array has to be found along with it's index. So I return an object where the i property is the index and the e property is the first duplicate element itself. One way of performing this task would be

var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3],
    headDupe = (a,r={}) => (r.e = a.find((n,i) => (r.i = a.indexOf(n), r.i < i)),r);

console.log(headDupe(numbers4));
Redu
  • 25,060
  • 6
  • 56
  • 76