Ошибка при удалении дубликатов из массива Javascript

ОБНОВИТЬ

Вот небольшая проблема: https://jsfiddle.net/q9c5fku3/ когда я запускаю этот код и смотрю на консоль, я вижу, что это console.logging другого числа в массиве.

Спасибо за ваши ответы, извините, я получаю отрицательные отзывы, но это действительно смущает меня.

Я попробовал это снова, используя разные числа, интересно, вы, ребята, можете проверить эти цифры на своем конце и посмотреть, если вы получите другой результат?

    var myArray = [621608617992776, 621608617992776, 10156938936550295, 621608617992776, 10156938936550295, 10156938936550295, 621608617992776, 10156938936550295];
    console.log(myArray);

    var myArrayTrimmed = [];

    for(var i in myArray){
        if(myArrayTrimmed.indexOf(myArray[i]) === -1){
            myArrayTrimmed.push(myArray[i]);
        }
    }
    console.log(myArrayTrimmed);

Это дает мне следующий массив в консоли:

[621608617992776, 10156938936550296]

Почему-то второе число увеличилось на 1.

====================

Оригинальный вопрос:

У меня есть этот массив:

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200];

Я пытаюсь создать новый массив с именем myArrayTrimmed это будет то же самое как вышеупомянутый массив, за исключением того, что будут удалены дубликаты. Это должно привести к:

var myArrayTrimmed = [100, 200];

Вот код, который я использую, чтобы добиться этого:

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200];
var myArrayTrimmed = [];

for(var i in myArray){
    if(myArrayTrimmed.indexOf(myArray[i]) === -1){
        myArrayTrimmed.push(myArray[i]);
    }
}
console.log(myArrayTrimmed);

Это не работает правильно, в то время как он удаляет дубликаты, по некоторым причинам он вычитает число 1 от 200, поэтому вывод в консоли:

[100, 199]

Я думаю, что это должно быть связано с -1 в коде, но я не знаю, как еще удалить дубликаты.

3 ответа

Решение

Я считаю, что это лучший способ сделать это

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{}));
console.log(reduced);

Хорошо... хотя это O(n), а остальные O(n^2), мне было любопытно увидеть сравнение эталонных тестов между этой таблицей уменьшения / поиска и комбинацией filter/indexOf (я выбрал очень хорошую реализацию Jeetendras /questions/10960523/oshibka-pri-udalenii-dublikatov-iz-massiva-javascript/10960533#10960533). Я готовлю массив из 100КБ, заполненный случайными положительными целыми числами в диапазоне 0-9999, и он удаляет дубликаты. Я повторяю тест 10 раз, и средние результаты показывают, что они не совпадают по производительности.

  • В Firefox v47 уменьшить & lut: 14,85 мс против фильтра и indexOf: 2836 мс
  • В Chrome v51 уменьшение & lut: 23,90 мс против фильтра и indexOf: 1066 мс

Ну хорошо, пока все хорошо. Но давайте сделаем это правильно в этот раз в стиле ES6. Это выглядит так круто..! Но на данный момент, как он будет работать против мощного решения Lut, для меня загадка. Давайте сначала посмотрим код, а затем сравните его.

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];
console.log(reduced);

Вау, это было коротко..! Но как насчет производительности..? Это прекрасно... Так как большой вес фильтра / indexOf перевалил за наши плечи, теперь я могу протестировать массив 1M случайных элементов натуральных чисел в диапазоне 0..99999, чтобы получить среднее значение из 10 последовательных тестов. Я могу сказать, что на этот раз это настоящий матч. Смотрите результат для себя:)

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 10;
for (var i = 0; i<count; i++){
  ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

Какой бы вы использовали..? Ну, не так быстро...! Не обманывайтесь. Карта находится в смещении. Теперь посмотрите... во всех вышеупомянутых случаях мы заполняем массив размером n числами диапазона

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

Теперь это захватывающее возвращение Map()..! Может быть, теперь вы можете принять лучшее решение, когда вы хотите удалить обманщиков.

Ну ладно, теперь мы все счастливы. Но главная роль всегда идет с аплодисментами. Я уверен, что некоторые из вас задаются вопросом, что будет делать объект Set. Теперь, когда мы открыты для ES6 и знаем, что Map - победитель предыдущих игр, давайте сравним Map с Set как финал. На этот раз типичная игра "Реал Мадрид - Барселона"... или это так? Посмотрим, кто победит в эль классико:)

var ranar = [],
     red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     red2 = a => Array.from(new Set(a)),
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("map & spread took: " + avg1 + "msec");
console.log("set & A.from took: " + avg2 + "msec");

Вау.. человек..! Что ж, неожиданно это вовсе не оказалось el classico. Больше похоже на ФК Барселона против CA Osasuna:))

Вы можете использовать приведенный ниже код для эффективного удаления дублирующихся элементов -

var myArrayTrimmed = myArray.filter(function(elem, pos) {
return myArray.indexOf(elem) == pos;
});

myArrayTrimmed будет содержать уникальные значения.

Надеюсь, это будет полезно

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200];
var myArrayTrimmed = [];
myArray.forEach(function(item){
 if(myArrayTrimmed.indexOf(item) ==-1){
   myArrayTrimmed.push(item);
}

})
console.log(myArrayTrimmed);

Проверьте это jsfiddle

Другие вопросы по тегам