Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Удаление одинаковых элементов массива (https://javascript.ru/forum/events/45211-udalenie-odinakovykh-ehlementov-massiva.html)

Ваяс 19.02.2014 07:42

Удаление одинаковых элементов массива
 
Помогите удалить одинаковые элементы массива, оставляя те что не повторялись
var array = [1, 2, 1, 10, 5, 3, 4, 40, 50], i = array.length, result = [];

array.sort(function(a,b) {
    return b-a;
});

while(i--){
    if(result.join().search(array[i]+'\\b') == '-1') {
        result.push(array[i]);
    }
}

alert(result);

Т.е. если значение повторялось, его не пишем вообще
[2, 10, 5, 3, 4, 40, 50]

рони 19.02.2014 12:45

Ваяс,
:-?
var array = [1, 2, 1, 10, 5, 3, 4, 40, 50],
     i = array.length,
     result = [];
 array.sort(function (a, b) {
     return a - b;
 });
 for (var i = 0; i < array.length; i++) {
     array[i] != array[i - 1] && array[i + 1] != array[i] && result.push(array[i])
 }
 alert(result);

Deff 19.02.2014 15:55

var arr = [1, 2, 1, 10, 5, 3, 4, 40, 50],
bound = '\n\n===@@@==\n\n',
tststr = bound + arr.join(bound+bound) + bound,
out=[];
 for (var i = 0; i < arr.length; i++) {
     if(tststr.split(bound +arr[i] + bound).length <3)out.push(arr[i])
 }
alert(out)

danik.js 19.02.2014 16:06

Цитата:

Сообщение от Deff
bound = '\n\n==123==\n\n'

Вместо этих ужасных костылей лучше es5-shim.js подключить (или выковырять только функцию Array.prototype.indexOf)

Deff 19.02.2014 16:23

danik.js,
:) У меня до сих пор на сервисе требование Ие7
1. Костыль не длиннее
2. Если разобрать исходники, всё в конце концов делается через строчные операторы, т.е по идее скорость обработки должна возрастать
3. Для данного случая можно bound = ','

danik.js 19.02.2014 16:57

Цитата:

Сообщение от Deff
У меня до сих пор на сервисе требование Ие7

es5-shim.js работает даже в IE5.5 если ты не в курсе. Так что не знаю к чему твой довод
1) Не длинее, но ужаснее, плюс имеет ограниченную применимость, в отличие от [].indexOf
2) Ха-ха, будешь мне тут за скорость говорить, когда у тебя на каждой итерации идет создание массива через split()
3) Вот именно. К чему было бороду лепить.

Deff 19.02.2014 18:29

Цитата:

Сообщение от danik.js
1) Не длинее, но ужаснее,

:) Имхо: А что твоё мнение определяющее во всём инете ?
Мне например Ван Гог не импонирует...
Цитата:

плюс имеет ограниченную применимость, в отличие от [].indexOf
Приведи пример, второе: Вы слишком серьёзно подходите к кодам выложенным в качестве развлечения!
Цитата:

Сообщение от danik.js
2) Ха-ха, будешь мне тут за скорость говорить, когда у тебя на каждой итерации идет создание массива через split()

Выложи свой код, создадим тест сравнения, для текстовых переменных как то тестировал, (ксать не оптимизировал пока по скорости

danik.js 19.02.2014 20:05

Цитата:

Сообщение от Deff
Выложи свой код

var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
var result = [];
for (var i = 0; i < array.length; i++) {
    var item = array[i];
    if (array.indexOf(item, i + 1) === -1 && (i === 0 || array.lastIndexOf(item, i - 1) === -1))
        result.push(item);
}
alert(result);

danik.js 19.02.2014 20:10

Цитата:

Сообщение от Deff
создадим тест сравнения

Ну что ж, давай!

/**
 * @author danik.js
 **/
function test1() {
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
    var result = [];
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        if (array.indexOf(item, i + 1) === -1 && (i === 0 || array.lastIndexOf(item, i - 1) === -1))
            result.push(item);
    }
    return result;
}

/**
 * @author Deff
 **/
function test2() {
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
    var bound = ',';
    var tststr = bound + array.join(bound+bound) + bound;
    var result = [];
     for (var i = 0; i < array.length; i++) {
        var item = array[i];
        var t = bound +item + bound;
        if (tststr.indexOf(t) === tststr.lastIndexOf(t))
            result.push(item);
     }
    return result;
}

/**
 * @author рони
 **/
function test3() {
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
    var result = [];
    array.sort(function (a, b) {
        return a - b;
    });
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        if (item != array[i - 1] && array[i + 1] != item)
            result.push(item);
    }
    return result;
}



/**
 * @author Дзен-трансгуманист (danik.js edition)
 **/
function test4(){
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
    var uniqueness = [];
    var result = [];
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        switch (uniqueness[item]) {
          case undefined:
              uniqueness[item] =  true;
              break;
          case true:
              uniqueness[item] = false;
        }
    }

    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        if (uniqueness[item])
            result.push(item);
    }
    return result;
}

/**
 * @author BallsShaped
 **/
function test6(){
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
    var result = [];
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        if (array.indexOf(item) == array.lastIndexOf(item))
            result.push(item);
    }
    return result;
}

/**
 * @author Дзен-трансгуманист
 **/
function test5(){
  var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
  var uniqueness = new Map();
  var result = [];

  for ( var i = 0; i < array.length; i++ ) {
    var value = array[ i ];
    switch ( uniqueness.get( value )) {
      case undefined: uniqueness.set( value, true ); return;
      case true: uniqueness.set( value, false );
    }
  }

  for ( var i = 0; i < array.length; i++ ) {
      var item = array[ i ];
      if ( uniqueness.get( value ) )
        result.push( item );
  }
  return result;
}

console.time('danik.js');
for (var i = 0; i < 1000000; i++)
    test1();
console.timeEnd('danik.js')



console.time('Deff');
for (var i = 0; i < 1000000; i++)
    test2();
console.timeEnd('Deff')



console.time('рони');
for (var i = 0; i < 1000000; i++)
    test3();
console.timeEnd('рони')

console.time('Дзен-трансгуманист (danik.js edition)');
for (var i = 0; i < 1000000; i++)
    test4();
console.timeEnd('Дзен-трансгуманист (danik.js edition)')

console.time('BallsShaped');
for (var i = 0; i < 1000000; i++)
    test6();
console.timeEnd('BallsShaped')

console.time('Дзен-трансгуманист');
for (var i = 0; i < 1000000; i++)
    test5();
console.timeEnd('Дзен-трансгуманист')


Мои результаты в хроме:
Код:

danik.js: 725.000ms
Deff: 5175.000ms
рони: 1448.000ms

Хорошо бы конечно генерить рандомные массивы разного размера, но как-то лень мне...
Думаю на больших массивах вариант рони окажется быстрей.

BallsShaped 19.02.2014 20:19

То ли я задачу не понял, то ли это конкурс самого нечитаемого кода. Не проще ли так:
.filter(function (item, index, array) {
    return array.indexOf(item) == index;
})

danik.js 19.02.2014 20:28

BallsShaped, не правильно ты понял. Если элемент имеет дубль - то ни он, ни его дубль не попадает в результат. В результат попадают только уникальные элементы.

danik.js 19.02.2014 20:31

рони, не вижу своего варианта :D

danik.js 19.02.2014 20:34

И сделай bound запятую. И вобще, я же уже вычистил код и привел единому виду. Лучше сделай генерацию рэндомных массивов.

Дзен-трансгуманист 19.02.2014 20:35

EcmaScript 6 Map

function uniquesOnly ( source ) {

  var uniqueness = new Map();

  source.forEach( function ( value ) {
    switch ( uniqueness.get( value )) {
      case undefined: uniqueness.set( value, true ); return;
      case true: uniqueness.set( value, false );
    }
  });

  return source.filter( function ( value ) {
    return uniqueness.get( value );
  });
}

alert(uniquesOnly([1, 2, 1, 10, 5, 3, 4, 40, 50]));

рони 19.02.2014 20:38

:write: убрал сравнение копипаст был неудачным )))

Дзен-трансгуманист 19.02.2014 20:46

Ну че, запилете мою функцию в тесты? ))))

danik.js 19.02.2014 20:56

Дзен-трансгуманист, интересный вариант :victory:
Думаю в случае с числовым/строчным массивом уместен упрощенный вариант:

var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
var uniqueness = {};
for (var i = 0; i < array.length; i++) {
    var item = array[i];
    switch (uniqueness[item]) {
      case undefined:
          uniqueness[item] =  true;
          break;
      case true:
          uniqueness[item] = false;
    }
}

var result = array.filter(function (value) {
    return uniqueness[value];
});

alert(result);

рони 19.02.2014 21:02

:) обычно я делал так ... новый вариант и сравнение
var time_roni = new Date
for (var a=0; a<10000; a++)  {
    var array = [1, 2, 1, 10, 5, 3, 4, 40, 50],
     tmp = {},
     result = [];
 for (var i=0; i<array.length; i++)  {tmp[array[i]] = tmp[array[i]]?++tmp[array[i]]:1}
 for (var i = 0; i < array.length; i++) {
      tmp[array[i]] == 1 && result.push(array[i])
 }

  }
var time_roni = (new Date).getTime() - time_roni.getTime() ;
function uniquesOnly ( source ) {

  var uniqueness = new Map();

  source.forEach( function ( value ) {
    switch ( uniqueness.get( value )) {
      case undefined: uniqueness.set( value, true ); return;
      case true: uniqueness.set( value, false );
    }
  });

  return source.filter( function ( value ) {
    return uniqueness.get( value );
  });
}
var time_dzen = new Date
for (var a=0; a<10000; a++)  {
uniquesOnly([1, 2, 1, 10, 5, 3, 4, 40, 50]);
                           }
var time_dzen = (new Date).getTime() - time_dzen.getTime() ;
var time_danik  = new Date
for (var a=0; a<10000; a++)  {
var array = [1, 2, 1, 10, 5, 3, 4, 40, 50];
var result = [];
for (var i = 0; i < array.length; i++) {
    var item = array[i];
    if (array.indexOf(item, i + 1) === -1 && (i === 0 || array.lastIndexOf(item, i - 1) === -1))
        result.push(item);
}
}
var time_danik = (new Date).getTime() - time_danik.getTime() ;
alert([time_roni,time_dzen,time_danik])

BallsShaped 19.02.2014 21:18

.filter(function (item, index, array) {
    return array.indexOf(item) == array.lastIndexOf(item);
})

danik.js 19.02.2014 21:49

BallsShaped, ловко )
Обновил тесты. Не заметил что код рони модифицирует исходный массив.
Добавил вариант шарика, переписал циклы на простой for().

Вариант с Map() самый быстрый в хроме!
Цитата:

danik.js: 715.000ms
Deff: 4801.000ms
рони: 1662.000ms
Дзен-трансгуманист (danik.js edition): 1519.000ms
BallsShaped: 951.000ms
Дзен-трансгуманист: 380.000ms

Deff 19.02.2014 21:53

var arr = [],
arrLng = 6000,
out=[];
 for (var i = 0; i < arrLng; i++) {
     arr.push(parseInt(Math.random()*arrLng))
 }


//====== Deff =========
var st = +new Date(),
bound = ',';
out=[];
var tststr = bound + arr.join(bound+bound) + bound;
 for (var i = 0; i < arr.length; i++) {
     var t = bound +arr[i] + bound;
     if(tststr.indexOf(t)==tststr.lastIndexOf(t))out.push(arr[i])
 }
var work = +new Date()-st;
alert('Deff ='+work+'\n\n'+out)


//===== danik ==========
var st = +new Date();
out=[];
for (var i = 0; i < arr.length; i++) {
    var item = arr[i];
    if (arr.indexOf(item, i + 1) === -1 && (i === 0 || arr.lastIndexOf(item, i - 1) === -1))
        out.push(item);
}
var work = +new Date()-st;
alert('danik ='+work+'\n\n'+out)


//===== рони ==========
var st = +new Date();
out=[];
arr.sort(function (a, b) {
return a - b;
});
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item != arr[i - 1] && arr[i + 1] != item)
out.push(item);
}
var work = +new Date()-st;
alert('рони ='+work+'\n\n'+out)


В Опере 12.6 и Ие быстрее первая метода, в Хроме и Мозилле - вторая

danik.js 19.02.2014 22:06

Deff, обновил твой вариант у себя в тесте. Все-равно твой код самый медленный.

danik.js 19.02.2014 22:08

Цитата:

Сообщение от Deff
и Ие

Ты серьзено? :D
Ну да ладно, из-за академического интереса ради, разве что.

danik.js 19.02.2014 22:17

Цитата:

Сообщение от Deff
Ие

А какой ие? Мерил в 10м - там твой вариант все равно медленней, процентов на 30%
А в опере да, быстрей, но там разница в считанные проценты. Вобще, опера тормозит жутко.

Deff 19.02.2014 22:20

Походу в WEBkit работа с массивами уже переведена на аппаратный уровень

Deff 19.02.2014 22:25

Цитата:

Сообщение от danik.js
Deff, обновил твой вариант у себя в тесте. Все-равно твой код самый медленный.

1. Твой тест не сильно валидный, ибо см у меня, я начальные установки все Вынес за пределы измерений, либо нужно делать достаточно длинный массив, чтоб установка стартовых условий мало влияла

И чот твой тест (пост 9) у меня из топика не запускается
================================================
И вообще, по сравнению с рони, мы все в жопе.. (правдо меняется порядок элементов, хотя наверно и при восстановлении старого порядка следования всё одно выиграет

Дзен-трансгуманист 19.02.2014 23:11

Цитата:

Сообщение от Deff
по сравнению с рони, мы все в жопе

:lol:

Цитата:

Сообщение от danik.js
Дзен-трансгуманист (danik.js edition): 1519.000ms
Дзен-трансгуманист: 380.000ms

Вероятно, твой вариант медленнее из-за преобразования чисел в строку.


А вообще, прикольно видеть, когда на такую, казалось бы, простую задачку возникает целая куча решений.
Коллективный мозговой штурм - это и для ума полезно, и для души приятно. :)

Deff 19.02.2014 23:15

Ксать поправил начальные условия в своём тесте , походу всех обогнал ?
Гы, нашел , где лажа

danik.js 19.02.2014 23:26

Deff, с какой это стати не учитываешь время на создание строки?

Deff 19.02.2014 23:27

Цитата:

Сообщение от Дзен-трансгуманист
Вероятно, твой вариант медленнее из-за преобразования чисел в строку.

Да, собственно делал нечто подобное, во время появления Опера v12.54, тогда было быстрее во всех браузерах
теперь походу в в WEBkit работа с массивами уже переведена на аппаратный уровень
В опере 12.6 и сейчас чуть быстрее danik.js

Дзен-трансгуманист 19.02.2014 23:35

Цитата:

Сообщение от Deff
походу в в WEBkit работа с массивами уже переведена на аппаратный уровень

ага, ага, прямо на GPU :D

Deff 19.02.2014 23:40

Дзен-трансгуманист,
Ну я имею ввиду чо ранее был интерпретатор, в сейчас для функций массивов уже скомпилированный код

danik.js 19.02.2014 23:45

Цитата:

Сообщение от Дзен-трансгуманист
из-за преобразования чисел в строку

Я понимаю. Попытался чуть-чуть отыграть заменив объект дырявым массивом. Кстати, интересует вопрос: доступ к свойствам объекта отличается от доступа к элементам массива?
То есть какие отличия {0:'a'}[0] от ['a'][0] ? Преобразование нуля в строку идет в обоих случаях?

danik.js 19.02.2014 23:58

Кстати, почему-то в хроме доступ к свойствам, если явно использовать строки в качестве ключей, медленней раз в десять..

(function(){
    var o = {0:'a', 1: 'b'};
    console.time('t2');
    for (var j = 0; j < 100000000; j++) {
        o['0'];
        o['1'];
    }
    console.timeEnd('t2');
})();
(function(){
    var o = {0:'a', 1: 'b'};
    console.time('t');
    for (var j = 0; j < 100000000; j++) {
        o[0];
        o[1];
    }
    console.timeEnd('t');
})();

Deff 20.02.2014 00:13

Cваял версию 2
var arr = [],
arrLng = 6000,
out=[];
 for (var i = 0; i < arrLng; i++) {
     arr.push(parseInt(Math.random()*arrLng))
 }


//====== Deff =========
var st = +new Date(),
bound = ',';
out=[];
var tststr = bound + arr.join(bound) + bound;
 for (var i = 0; i < arr.length; i++) {
     var t = bound +arr[i] + bound;
     if(tststr.indexOf(t)==tststr.lastIndexOf(t))out.push(arr[i])
 }
var work = +new Date()-st;
alert('Deff ='+work+'\n\n'+out)



//====== Deff v2 =========
var st = +new Date(),
obj ={};
out=[];
 for (var i = 0; i < arr.length; i++) {
     if(obj[arr[i]]){obj[arr[i]]='D'} //Дубль
     else  obj[arr[i]] = i;
 }
 for (var key in obj) {
    if(obj[key]!='D') out[obj[key]] = key
 }
 out = out.join(',').replace(/^,+/,'').replace(/,+$/,'').split(/,+/)
var work = +new Date()-st;
alert('Deff v2 ='+work+'\n\n'+out)


//===== danik ==========
var st = +new Date();
out=[];
for (var i = 0; i < arr.length; i++) {
    var item = arr[i];
    if (arr.indexOf(item, i + 1) === -1 && (i === 0 || arr.lastIndexOf(item, i - 1) === -1))
        out.push(item);
}
var work = +new Date()-st;
alert('danik ='+work+'\n\n'+out)


//===== рони ==========
var st = +new Date();
out=[];
arr.sort(function (a, b) {
return a - b;
});
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item != arr[i - 1] && arr[i + 1] != item)
out.push(item);
}
var work = +new Date()-st;
alert('рони ='+work+'\n\n'+out)

Дзен-трансгуманист 20.02.2014 00:20

Цитата:

Сообщение от danik.js
Кстати, интересует вопрос: доступ к свойствам объекта отличается от доступа к элементам массива?

Угу, отличается: Properties of Array Instances

Цитата:

Array objects use a variation of the [[DefineOwnProperty]] internal method used for other native ECMAScript objects.

Дзен-трансгуманист 20.02.2014 00:38

Цитата:

Сообщение от danik.js
То есть какие отличия {0:'a'}[0] от ['a'][0] ? Преобразование нуля в строку идет в обоих случаях?

Что там происходит физически - хз. Каждый движок по-своему реализует соответствие спецификации.
Но многих операций в теории можно избежать с помощью всяких эвристических оптимизаций.
Например, движок может не определять у массива свойство length, если анализ семантического дерева показывает, что оно ни разу не используется.
А может не то что не определять никаких свойств, а даже и вообще не создавать "JS-объект" как таковой: если известно, что аксессоры используют только ключи целочисленного типа, то достаточно выделить голый индексированный список с простой интеграцией ссылок в инфраструктуру сборщика мусора. Накладные расходы будут близки к минимальным.

danik.js 20.02.2014 01:16

Цитата:

Сообщение от Deff
Cваял версию 2

Не очень то она отличается от уже предложенной :D

Отбросил медленные варианты:

(function(){

var array = [],
arrayLength = 6000;
for (var i = 0; i < arrayLength; i++) {
    array.push(parseInt(Math.random()*arrayLength));
}

/**
 * @author рони
 **/
function test1() {
    var result = [];
    var clone = array.slice();
    clone.sort(function (a, b) {
        return a - b;
    });
    for (var i = 0; i < clone.length; i++) {
        var item = clone[i];
        if (item != clone[i - 1] && clone[i + 1] != item)
            result.push(item);
    }
    return result;
}

/**
 * @author Deff
 **/
function test2() {
var obj ={};
var result = [];
    for (var i = 0; i < array.length; i++) {
        if(obj[array[i]]){
            delete obj[array[i]];
            continue;
        }
        obj[array[i]] = i;
    }
    for (var key in obj) {
        result[obj[key]] = key;
    }
    result = result.join(',').replace(/^,+/,'').replace(/,+$/,'').split(/,+/);

    return result;
}

/**
 * @author Дзен-трансгуманист (danik.js edition)
 **/
function test3(){
    var uniqueness = [];
    var result = [];
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        switch (uniqueness[item]) {
          case undefined:
              uniqueness[item] =  true;
              break;
          case true:
              uniqueness[item] = false;
        }
    }
 
    for (var i = 0; i < array.length; i++) {
        var item = array[i];
        if (uniqueness[item])
            result.push(item);
    }
    return result;
}

/**
 * @author Дзен-трансгуманист
 **/
function test4(){
  var uniqueness = new Map();
  var result = [];
 
  for ( var i = 0; i < array.length; i++ ) {
    var value = array[ i ];
    switch ( uniqueness.get( value )) {
      case undefined: uniqueness.set( value, true ); break;
      case true: uniqueness.set( value, false );
    }
  }
 
  for ( var i = 0; i < array.length; i++ ) {
      var item = array[ i ];
      if ( uniqueness.get( value ) )
        result.push( item );
  }
  return result;
}

console.time('рони');
for (var i = 0; i < 100; i++)
    test1();
console.timeEnd('рони')

console.time('Deff');
for (var i = 0; i < 100; i++)
    test2();
console.timeEnd('Deff')

console.time('Дзен-трансгуманист (danik.js edition)');
for (var i = 0; i < 100; i++)
    test3();
console.timeEnd('Дзен-трансгуманист (danik.js edition)')

console.time('Дзен-трансгуманист');
for (var i = 0; i < 100; i++)
    test4();
console.timeEnd('Дзен-трансгуманист')

})();


В хроме вариант с Map() на большом массиве медленней чем с []. В файрфоксе наоборот...

Deff 20.02.2014 01:24

danik.js,
У меня не запускается твой тест ни в одном из браузеров


danik.js 20.02.2014 01:38

Deff, консоль открой. От тебя не ожидал )))
Чтоб отработал вариант с Map() надо в chrome://flags включить harmony
В фф не знаю, у меня работает. Обнови фф или покопайся в настройках.


Часовой пояс GMT +3, время: 02:44.