Найти одинаковые элементы в массиве

Тема в разделе "JavaScript", создана пользователем Extremosa, 14 мар 2020.

XEvil 4.0 Релиз Состоялся!
Метки:
  1. garphild

    garphild Постоялец

    Регистр.:
    19 май 2009
    Сообщения:
    56
    Симпатии:
    31
    Есть не менее быстрый вариант с использованием той же идеи что в моем примере, но с использованием новых фишек языка. Стало более читабельно даже.
    Код:
    var array = [];
    var limit = 10000;
    function getRandom(limit) {
      return Math.floor(Math.random() * Math.floor(limit));
    }
    for(var i=0; i<limit; i++){
      array.push(String(getRandom(limit)));
    }
    
    var time = new Date().getTime();
    array.reduce((agg,col) => {
      agg.filter[col] = agg.filter[col]? agg.dup.push(col): 2;
      return agg
    },
    {filter:{},dup:[]})
    .dup;
    console.log(new Date().getTime() - time); // 2
    Есть еще варианты на других библиотеках. Например lodash.
    Код:
    var array = [];
    var limit = 10000;
    function getRandom(limit) {
      return Math.floor(Math.random() * Math.floor(limit));
    }
    for(var i=0; i<limit; i++){
      array.push(String(getRandom(limit)));
    }
    
    var time = new Date().getTime();
    const dup = _(array)
        .countBy()
        .reduce((acc, val, key) => val > 1 ? acc.concat(key) : acc, [])
        .map(_.toNumber)
    
    // console.log(dup);
    console.log(new Date().getTime() - time); // 43
    
    Код:
    var array = [];
    var limit = 10000;
    function getRandom(limit) {
      return Math.floor(Math.random() * Math.floor(limit));
    }
    for(var i=0; i<limit; i++){
      array.push(String(getRandom(limit)));
    }
    var time = new Date().getTime();
    function getDuplicate(array){
      var doubles = {};
      array.forEach((v) => doubles[v] = doubles[v] ? doubles[v] + 1 : 1);
      doubles = Object.keys(doubles).filter((v) => doubles[v] > 1);
      return doubles;
    }
    getDuplicate(array);
    console.log(new Date().getTime() - time); // 2
    Код:
    var array = [];
    var limit = 10000;
    function getRandom(limit) {
      return Math.floor(Math.random() * Math.floor(limit));
    }
    for(var i=0; i<limit; i++){
      array.push(String(getRandom(limit)));
    }
    
    var time = new Date().getTime();
    var groupped = _.groupBy(array, function (n) {return n});
    var result = _.uniq(_.flatten(_.filter(groupped, function (n) {return n.length > 1})));
    console.log(new Date().getTime() - time); // 10
    Код:
    var array = [];
    var limit = 10000;
    function getRandom(limit) {
      return Math.floor(Math.random() * Math.floor(limit));
    }
    for(var i=0; i<limit; i++){
      array.push(String(getRandom(limit)));
    }
    
    var time = new Date().getTime();
    _(array).groupBy().pickBy(x => x.length > 1).keys().value()
    console.log(new Date().getTime() - time); // 7
     
    Extremosa и Absolute нравится это.
  2. sempais8

    sempais8 Писатель

    Регистр.:
    18 окт 2015
    Сообщения:
    8
    Симпатии:
    8
    2 garphild
    Хорошо, что есть необходимые знания, а фишки языка и библиотеки, это всего лишь инструмент!
     
  3. Absolute

    Absolute Крокодил ;)

    Регистр.:
    9 авг 2009
    Сообщения:
    559
    Симпатии:
    425
    c reduce - намудрили))
    Например, на массиве ТС будут дубли и всё равно приходим к дополнительному циклу.
    Код:
    var array = ['Весна', 'Осень', 'Зима', 'Зима', 'Лето', 'Зима', 'Осень'];
    
    var result = array.reduce((agg,col) => {
      agg.filter[col] = agg.filter[col]? agg.dup.push(col): 2;
      return agg
    },
    {filter:{},dup:[]})
    .dup;
    
    
    console.log(result); //["Зима", "Зима", "Осень"]
    PS: в подобных тестах от производительности среды запуска и конкретной машины могут результаты различаться для одного и того же кода.
     
    Последнее редактирование: 16 мар 2020
    garphild нравится это.
  4. garphild

    garphild Постоялец

    Регистр.:
    19 май 2009
    Сообщения:
    56
    Симпатии:
    31
    Сгласен. Это чуть перемудрил. Только тогда не к допциклу, а просто к unique. или же к группировке. и по производительности тогда вариант будет отставать. Просто красивый вариант с новыми фишками.
     
  5. Absolute

    Absolute Крокодил ;)

    Регистр.:
    9 авг 2009
    Сообщения:
    559
    Симпатии:
    425
    Почти все методы, работающие с массивами - те же циклы внутри.
    Просто выполните код:
    Код:
    console.log($.unique)
    И посмотрите как реализован метод в том же jQuery. Не знаю есть этот метод в нативе, но если есть будет плюс/минус похожая реализация, как минимум с одним циклом.
     
    garphild нравится это.
  6. garphild

    garphild Постоялец

    Регистр.:
    19 май 2009
    Сообщения:
    56
    Симпатии:
    31
    По сути да. Я имел в виду дополнительный цикл в самом коде уже внешней программы.
    Респект. Вообще мало кто из современных программистов задумывается о том, как работает внутри библиотека. Практически постоянно сталкиваюсь с тем, что люди для выполнения простейшей операции (типа вот этой) тащат в проект целую здоровенную библиотеку и даже не думают о том, что она может быть мягко говоря не оптимальна по производительности. Сейчас ресурс железа стоит меньше времени программиста. Поэтому фраза "да че там, сделал по быстряку. Если что - еще сервер докупим" становится финансово обоснованным возражением на тему "чего твои участки кода так медленно работают" (постарался мягко переформулировать диалог :). Правда если на это посмотреть реально в перспективе, то становится печально.
     
    Absolute нравится это.
  7. v3w

    v3w Писатель

    Регистр.:
    10 фев 2015
    Сообщения:
    6
    Симпатии:
    0
    Есть же там свойство map потом sort и unique
     
  8. comua

    comua Постоялец

    Регистр.:
    26 фев 2008
    Сообщения:
    111
    Симпатии:
    31
    Не совсем в тему, но... в стандарте ES6 есть встроенный объект Set

    Но есть пару моментов - поддержка старых браузеров и чувствительность к регистру.

    Код:
    let arr = ['Весна', 'Осень', 'Зима', 'Зима', 'Лето', 'Зима', 'Осень'];
    
    console.log([...new Set(arr)])
    
    // ["Весна", "Осень", "Зима", "Лето"]
    
    let arrCase = ['Весна', 'Осень', 'зима', 'Зима', 'Лето', 'Зима', 'осень'];
    
    console.log([...new Set(arrCase)]);
    
    // ["Весна", "Осень", "зима", "Зима", "Лето", "осень"]
     
  9. Absolute

    Absolute Крокодил ;)

    Регистр.:
    9 авг 2009
    Сообщения:
    559
    Симпатии:
    425
    Я пробовал переписывать через Set - работает быстро, но медленнее, чем вариант garphild через свойства объектов.
    У меня по итогу получился такой код самым быстрым с одним циклом на ES5 для поставленной ТС задачи:
    HTML:
    function getDuplicate(arr){
        var result = [], temp = {};
        arr.forEach(function(a){
          if (a in temp) {
             if (temp[a]) {
               result.push(a);
               temp[a] = false;
             }
           } else {
             temp[a] = true;
           }
        });
        return result;
    }
     
    Последнее редактирование: 21 май 2020