Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Как найти различие между двумя массивами? (https://javascript.ru/forum/offtopic/43511-kak-najjti-razlichie-mezhdu-dvumya-massivami.html)

Maxmaxmaximus4 09.12.2013 01:04

cyber, чувак, сделай фикс уже search.indexOf(this[i], i);

cyber 09.12.2013 01:08

Цитата:

Сообщение от Maxmaxmaximus4
cyber, чувак, сделай фикс уже search.indexOf(this[i], i);

Эм, понял о чем ты, я не увидел)

cyber 09.12.2013 01:20

Maxmaxmaximus4, ну тогда в общем replace не нужен:)

Maxmaxmaximus4 09.12.2013 01:36

Цитата:

Сообщение от cyber
ну тогда в общем replace не нужен

МНЕ - нужен, ну то есть собрать из старого массива новый используя только ремувы и инсерты я уже могу, реплейс это оптимизация, щас сижу добавляю его (реплейс это просто индексы значение которых надо поменять)

как ты вообще этот алгоритм придумал????????????????????????? сколько времени заняло? делал ли что-то подобное до этого? не ну, то есть , алгоритм то конечно тупой и брутальный, но РАБОТАЕТ ЖЕ)

cyber 09.12.2013 01:40

Maxmaxmaximus4, когда курсовую писал, нужно было сравнить 2 массива с изображениями что бы не перезагружать все, а разбираться с готовыми алгоритмами было влом поэтому сделал "в лоб".

Maxmaxmaximus4 09.12.2013 01:45

cyber, не ну, то есть , алгоритм то конечно тупой и брутальный, но РАБОТАЕТ ЖЕ) спасибо огромное

l-liava-l 09.12.2013 02:41

Ихих ребят вы чо, сравнение массивов по 2000 элементов из за парочки изменений это тоже не круто.

Цитата:

Конечно кто-то из вас скажет - просто сделай обертки на методы массива такие как pop push unshift и.т.п. и смотри как они вызываются и запоминай это, но я считчаю это костылем при чем грубым.
Можно же не переопределять свойства Array.prototype, а сделать другой обьект, который будет перекрывать эти свойства для твоих sсope обьектов. Вреда вообще никакого, и считаться будет быстрее)

Maxmaxmaximus4 09.12.2013 02:57

Цитата:

Сообщение от l-liava-l
Можно же не переопределять свойства Array.prototype, а сделать другой обьект, который будет перекрывать эти свойства для твоих sсope обьектов. Вреда вообще никакого, и считаться будет быстрее)

Не ну так я про то и говорю, ну перекрыли мы а человек новый аррей добавил, а что если этот новый аррей на 80% похож на старый? а что если человек использовал свои кастомные методы работы с массивом?
а что если человек через цикл for массив изменял? а что если концатенацией делал? вот и я про то)

Maxmaxmaximus4 09.12.2013 03:13

var oldArray = [1, 2, 3, 4, 5];
var newArray = [11, 3, 4, 3, 11, 21];

var changes = compare(oldArray, newArray);
console.log(changes);


// превратим старый аррей в новый используя полученные данные

// удаляем (в обратном порядке чтобы индексы не смещались)
for (var i = changes.remove.length - 1; i >= 0; i--) {
  var index = changes.remove[i];
  oldArray.splice(index, 1);
}
// добавляем
for (var i = 0; i < changes.insert.length; i++) {
  var index = changes.insert[i];
  oldArray.splice(index, 0, newArray[index])
}
// изменяем
for (var i = 0; i < changes.replace.length; i++) {
  var index = changes.replace[i];
  oldArray[index] = newArray[index];
}

// отобразим результат, старый и новый массивы теперь равны
console.log(newArray);
console.log(oldArray);



// наща мега функция
function compare(oArr, arr) {
  var search = arr.slice();
  var changes = {
    insert : [],
    remove : [],
    replace: []
  }

  for (var i = 0, index; i < oArr.length; i++) {
    index = search.indexOf(oArr[i], i);
    if (index < 0) changes.remove.push(i);
    else delete search[index];
  }

  for (var i = 0; i < search.length; i++) if (i in search) {
    var index = changes.remove.indexOf(i);
    if (index < 0) changes.insert.push(i);
    else {
      changes.remove.splice(index, 1);
      changes.replace.push(i)
    }
  }
  
  return changes
}

l-liava-l 09.12.2013 03:23

Цитата:

Не ну так я про то и говорю, ну перекрыли мы а человек новый аррей добавил, а что если этот новый аррей на 80% похож на старый? а что если человек использовал свои кастомные методы работы с массивом?
а что если человек через цикл for массив изменял? а что если концатенацией делал? вот и я про то)
А если не добавил? зачем тогда сравнивать столько элементов? Может запилить что то гибридное.

Maxmaxmaximus4 09.12.2013 03:24

ахаха суууука, оно не схавало ((
var oldArray = [1, 2, 3, 4, 5];
var newArray = [5, 4, 3, 2, 1];
массивы после преобразования не равны и проблема именно не в преобразовании а в данных которые возвращает функция.




Цитата:

Сообщение от l-liava-l
Может запилить что то гибридное.

а что если добавил а мы просмотрели? элементы не обновятся.
а что если он сделал так arr[1000000] = 100;

cyber 09.12.2013 03:48

Maxmaxmaximus4, конечно не схавало, потому что ты изменил так что учитывается порядок и мне кажется оптимальнее менять на основе replace

Maxmaxmaximus4 09.12.2013 03:50

cyber, слушай все мои изменения это то что я добавил i в indexOf()
когда я убираю результат тот же, когда я использую твою функцию результат тот же)

Цитата:

Сообщение от cyber
оптимальнее менять на основе replace

немного не понял, ты к тому что replace менее дорогая операция и нам приемущественно выцеживать её чем ремувы и инсерты?

в принципе есть идейка небольшая как replace так прокачать чтобы вначале он все свои дела делал, чтобы все что можно заменить им, заменялось им.

cyber 09.12.2013 04:15

Maxmaxmaximus4,
какие данные у тебя в массиве лежат ? дом объекты ?

Maxmaxmaximus4 09.12.2013 04:52

Цитата:

Сообщение от cyber
какие данные у тебя в массиве лежат ? дом объекты ?

нет, любые данные, числа, обьекты, что угодно, блин а, ты что не знаешь как ui работает?

<script src='//mychamber.ru/build/ui.js'></script>

<div controller="Ctrl">
  Привет {name}, тебе {age} лет!
</div>

<script>
function Ctrl() {
    name = 'Ашот'
    age = 15
}
</script>



А тут короче надо будет сделать чтобы элемент повторялся столько раз сколько элементов в массиве, и значения элементов массива засовывались в переменную которую мы придумаем, например val

<div controller="Ctrl">
  <div repeat="val in arr">{val}</div>
</div>

<script>
function Ctrl() {
    arr = [1, 2, 3, 4]
}
</script>


и вот этот вот див внутренний повторится столько раз, сколько ячеек в массиве, и в каждом {val} будет иметь разное значение, суть в том чтобы при изменении массива элементы отражали его состояние. можно удалять каждый раз все созданные элементы и создавать новые и перерисовывать, но я хочу отражать только изменения, а для этого надо их отслеживать. все просто =)

Maxmaxmaximus4 09.12.2013 05:05

cyber, блин, и если честно я вообще не понимаю как твой алгоритм работает, ну то есть понимать то понимаю, но не понимаю почему то должно работать и как "учитывать порядок"

DjDiablo 09.12.2013 06:58

Цитата:

Привет Ашот, тебе 15 лет!
ты с лолей на мальчиков переключился ? ))))))))))

Чото дикую хреновину максимус ты придумал :)
Но в целом любопытно. Хотя поиск оптимального решения будет вероятно медленнее чем работа с dom. Вероятно нужно работать не с одним числом а с группами чисел (группы гораздо больше свидетельствуют о структуре чем отдельные числа). Так как последовательности чисел и групп можно объяснить по разному то мы получим дерево вариантов в котором нам придется искать кратчайший путь.

DjDiablo 09.12.2013 09:19

С другой стороны Я не уверен что разные объяснения как либо отражаются на структуре. Ну к примеру две последовательности 567 и 567567 можно объяснить как добавлением 567 слева так и добавлением 567 справа, это равнозначные варианты и выбрать можно любой.

окей если так посмотреть

33 2 567
33 4 567 3 567
здесь нам все равно было ли во втором случае 567 добавлено в конец или в середину

а вот здесь не все равно.
33 2 567 89 2 90
33 4 89 3 90 567

Вродебы 567 встречается и во втором случае.
Но у нас так же встречаются и 89 x 90.
если было добавлено 567 в конец то это три изменения
а если 89 90 в середину это аж четыре.
Вероятно 567 это добавленый элемент а не сохранившийся, так как добавление 567 потребует меньше трансформаций чем его сохранение. Ведь за сохранение трех чисел 567 мы вынуждены заплатить добавление аж 4х (89 x 90).

а вот ситуация по интереснее. В отличии от предыдущего примеру выбирать нужно между множеством обьяснений
1)
33 567 890 2 90 60
33 90 3 890 567 2 890 60
совпали 567 890 (6 совпадений)

2)
33 567 890 2 90 60
33 90 3 890 567 2 890 60
совпали 90 2 90 (5 совпадений)

3)
33 567 890 2 90 60
33 90 3 890 567 2 890 60
совпали 890 2 90 (6 совпадений)

4)
33 567 890 2 90 60
33 90 3 890 567 2 890 60
совпали 90 90 (4 совпадения)

5) ..... еще какие то

Гипотезы 1 и 3 требуют наименьшего числа изменений или можно сказать имеют наибольшее число совпадений между двумя массивами. Блядь, здесь как раз алгоритм Вагнера Фишера или алгоритм Хиршберга справляется :(

http://habrahabr.ru/post/117063/

P.S. 33 60 игнорирую чтобы не отвлекали, а так конечно они тоже участвуют
567 это не пятьсот шисят семь, а 5,6,7. Все числа от 0 до 9

BETEPAH 09.12.2013 09:56

Цитата:

Сообщение от Maxmaxmaximus4
<div controller="Ctrl">

а почему не <div data-controller="Ctrl">?

Maxmaxmaximus4 09.12.2013 12:09

Цитата:

Сообщение от DjDiablo
(группы гораздо больше свидетельствуют о структуре чем отдельные числа)

а я так и делал кстати) у меня в моей реализации было типа "участок с такого то индекса по такой-то - добавлен"

Цитата:

Сообщение от BETEPAH
а почему не <div data-controller="Ctrl">?

потому что припарсинге этот кастомный атрибут controller удаляется и в разметку попадает чистый html, а вообще ты можешь писать data-controller ui-controller ui:controller и.т.п. к тому же если добавят нативный атрибут controller который чо то делает, то когда человек писал приложение он явно имел ввиду именно наш контроллер а не тот нативный. если человек хочет использовать кастомный атрибут и нативный которые имеют одинаковое имя, то куда логичнее у нативным давать префикс чем кастомным так как кастомные встречаются куда чаще. по этому контроллеры человек будет обозначать так controller="Ctrl" а нативный атрибут контролллер так native-controller="true".

ntive-controller="true" заменится просто на controller='true', а controller="Ctrl" просто исчезнет из разметки. ну можно не native-, а nt-, не суть. Просто всегда бесило то что по какой-то неведомой причине люди тучу префиксов городят, по этому и начал писать свою либу, это одна из причин.

Это куда логичнее чем каждый раз городить тучу префиксов и захламлять код.

DjDiablo 09.12.2013 12:29

Цитата:

группы гораздо больше свидетельствуют о структуре чем отдельные числа
После анализа во втором своем посте (#58) Я уже не так уверен в этом. Слишком много возможных интерпретаций результатов сравнения двух массивов. Единственный способ оценить какая интерпритация верна это оценить ее стоимость(колво затраченных операций) или ценность (длинну комбинации). Очень может быть что простые алгоритмы для оценки стоимости которые уже разработаны, (почитать можно на хабре) окажутся эффективней чем выделение групп с последующим поиском наиболее оптимальной(читай длинной) комбинации.

Проверять все это в падлу и так отвлекся.

З.Ы. Стоимость это то что вы потратили, ценность это то что вы получили.

cyber 09.12.2013 13:27

Цитата:

Сообщение от Maxmaxmaximus4
нет, любые данные, числа, обьекты, что угодно, блин а, ты что не знаешь как ui работает?

А вдруг у ты изобрел что то новое, лучше уточнить)

cyber 09.12.2013 14:07

А почему бы не использовать бинарный поиск вместо indexOf, он же быстрее на сколько я вижу http://jsperf.com/binarysearch-vs-indexof/4
var BinarySearchBitshift = function (list, val) {
  	var min = 0
  	  , max = list.length-1
  	  ;
  	
  	for(;;)
  	{
  		// fall back to linear search, 11 seems to be a good threshold, but this depends on the uses comparator!! (here: ===)
  		if ( min + 11 > max ) {
  			for(var i=min ; i<=max; i++ ) {
  				if( val === list[i] ) {
  					return i;
  				}
  			}
  
  			return -1;
  		}
  
  		var mid = (min + max) >> 1;
  		var dat = list[ mid ];
  
  		if ( val === dat ) {
  			return mid;
  		} 
  
  		if( val > dat ) {
  			min = mid + 1;
  		} else {
  			max = mid - 1;
  		}
  	}
  };

рони 09.12.2013 14:20

:write:
function compare(f, d) {
    var e = {
        relocation: [],
        insert: [],
        length: d.length
    }, c = d + ", " + f ,
        b = f.slice();
    if (c = c.match(/([^,]\S*[^,])(?=,[\s\S]*\s[\s\S]*\1)/g)) {
        c.reverse();
        for (var a = 0; a < c.length; a++) {
            var g = ("" + b).slice(0, ("" + b).lastIndexOf(c[a]) + 1).split(",").length - 1,
                h = c[a].split(",").length,
                k = b.splice(g, h);
            e.relocation.push([g, h]);
            b = k.concat(b)
        }
    }
    for (a = 0; a < d.length; a++) d[a] != b[a] && (b.splice(a, 0, d[a]), e.insert.push([a, d[a]]));
    return e
};

function conversion(b, c) {
    for (var a = 0; a < c.relocation.length; a++) {
        var d = c.relocation[a];
        b = b.splice(d[0], d[1]).concat(b)
    }
    for (a = 0; a < c.insert.length; a++) d = c.insert[a], b.splice(d[0], 0, d[1]);
    b.length = c.length;
    return b
};

var oldArray = [1, 2, 3, 4, 5];
var newArray = [11, 3, 4, 3, 11, 21];
var changes = compare(oldArray, newArray);
var len = changes.relocation.length + changes.insert.length + 1;//кол-во затраченных операций в conversion
alert(newArray +"\n"+conversion(oldArray, changes)+"\n"+len)
var oldArray = [4, 50, 6, 7, 8, 9,1, 2, 3, 50 ];
var newArray = [1, 2, 4, 50, 6, 7, 8, 9,50];
var changes = compare(oldArray, newArray);
var len = changes.relocation.length + changes.insert.length + 1;
alert(newArray +"\n"+conversion(oldArray, changes)+"\n"+len)
var oldArray = [1, 2, 3, 4, 5];
var newArray = [5, 4, 3, 2, 1];
var changes = compare(oldArray, newArray);
var len = changes.relocation.length + changes.insert.length + 1;
alert(newArray +"\n"+conversion(oldArray, changes)+"\n"+len);
var oldArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var newArray = [1, 2, 3, 5, 34, 32, 4, 45];
var changes = compare(oldArray, newArray);
var len = changes.relocation.length + changes.insert.length + 1;
alert(newArray +"\n"+conversion(oldArray, changes)+"\n"+len);
var oldArray = [1, 2, 3, 4, 5];
var newArray = [1, 2, 3, 5, 4, 45];
var changes = compare(oldArray, newArray);
var len = changes.relocation.length + changes.insert.length + 1;
alert(newArray +"\n"+conversion(oldArray, changes)+"\n"+len);

monolithed 09.12.2013 15:11

Цитата:

Сообщение от cyber
А почему бы не использовать бинарный поиск вместо indexOf

Бинарный есть смысл использовать только на больших множествах.

cyber 09.12.2013 15:53

рони, скорость выполнения ужасная)
http://jsperf.com/compare-arrays-test

рони 09.12.2013 17:12

cyber,
сравнение количества операций для преобразования и длины нового массива ...
function rand()
{  var l = Math.round(Math.random() * 100), a = [];
   for (var i=0; i<l; i++)  {a[i]=Math.round(Math.random() * 100)}
   return a
}

function compare_indexOf(fArr,arr) {

    var search = arr.slice(),
        insert = [],
        remove = [],
        replace = [];

    for(var i = 0, index; i < fArr.length; i++) {

        index = search.indexOf(fArr[i]);

                if(!~index) {

                        remove.push(i);
            continue;
        }

       i != index &&  replace.push({'old': i, 'new': index});

        delete search[index];

        };

    search.forEach(function (elem, i) {
        if(elem)
          insert.push(i);
    });

    return {
        'remove': remove,
        'insert': insert,
        'replace': replace
    }

}
function compare(f, d) {
    var e = {
        relocation: [],
        insert: [],
        length: d.length
    }, c = d + ", " + f ,
        b = f.slice();
    if (c = c.match(/([^,]\S*[^,])(?=,[\s\S]*\s[\s\S]*\1)/g)) {
        c.reverse();
        for (var a = 0; a < c.length; a++) {
            var g = ("" + b).slice(0, ("" + b).lastIndexOf(c[a]) + 1).split(",").length - 1,
                h = c[a].split(",").length,
                k = b.splice(g, h);
            e.relocation.push([g, h]);
            b = k.concat(b)
        }
    }
    for (a = 0; a < d.length; a++) d[a] != b[a] && (b.splice(a, 0, d[a]), e.insert.push([a, d[a]]));
    return e
};
var oldArray = rand();
var newArray = rand();
var time_indexOf = new Date();
var changes = compare_indexOf(oldArray, newArray);
time_indexOf = (new Date()).getTime() - time_indexOf.getTime()
var len_indexOf = changes.remove.length + changes.insert.length + changes.replace.length;
var time = new Date();
var changes = compare(oldArray, newArray);
time = (new Date()).getTime() - time.getTime()
var len = changes.relocation.length + changes.insert.length + 1;
alert('len_indexOf : ' + len_indexOf + ' time: ' + time_indexOf + '\nlen: ' + len + ' time: ' + time + '\nlength : ' + newArray.length);

cyber 09.12.2013 17:21

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

П.с я не пытаюсь доказать что моя функция сравнения лучше, если честно мне всеравно, я оба варианта считаю слишком медленными и остойными)

рони 09.12.2013 17:40

Цитата:

Сообщение от cyber
почему у тебя нет массива с элементами которые нужно удалить?

так удалять то нечего )))
всё лишнее обрезается строкой
Цитата:

Сообщение от рони
b.length = c.length;


cyber 09.12.2013 17:41

рони, т.е нечего?
Если элемента нет во втором массиве, но есть в первом то его нужно удалить.

Maxmaxmaximus4 09.12.2013 17:50

сделайте кто нибудь чтобы оно порядок учитывало а то я мозг сломал)

cyber, чувак, выручай) ты придумал эту кашу, придумай как сделать чтобы она учитывала порядок и

12345 корректно превращалось в 54321, пожааалуйста ну пожаалуйста)!

рони 09.12.2013 17:50

Цитата:

Сообщение от cyber
Если элемента нет во втором массиве, но есть в первом то его нужно удалить.

можно написать цикл пока есть в oldArray элемент с индексом newArray.length его удалить - но можно проще просто изменить длину массива

рони 09.12.2013 17:52

Цитата:

Сообщение от Maxmaxmaximus4
порядок учитывало

или мой вариант это делает или обьясни про порядок

cyber 09.12.2013 17:53

Maxmaxmaximus4, ок, как только закончу с курсовой , посмотрю что можно придумать)

рони 09.12.2013 18:06

:write:
var changes = {
       insert : [[0, 5], [1, 4], [2, 3], [3, 2]],
       length : 5,
       relocation :	[]
   }
function conversion(b, c) {
    for (var a = 0; a < c.relocation.length; a++) {
        var d = c.relocation[a];
        b = b.splice(d[0], d[1]).concat(b)
    }
    for (a = 0; a < c.insert.length; a++) d = c.insert[a], b.splice(d[0], 0, d[1]);
    b.length = c.length;
    return b
};
alert( conversion([1, 2, 3, 4, 5],changes));
alert( conversion([1, 2, 3, 4, 5, 6, 7, 8, 20, 30],changes))

DjDiablo 09.12.2013 18:10

Рони
Я подставил значения
var oldArray = [3,3,5,6,7,8,9,0,2,9,0,6,0];
var newArray = [3,3,9,0,3,8,9,0,5,6,7,2,8,9,0,6,0];

У тебя 12 операций уходит, хотя достаточно девяти.

рони 09.12.2013 18:17

DjDiablo,
да скрипт не ставит найденные одинаковые цепочки сразу на свои места -- цепочки "доползают" до своего места по мере вставки недостающих элементов.

cyber 09.12.2013 18:36

Цитата:

Сообщение от рони
можно написать цикл пока есть в oldArray элемент с индексом newArray.length его удалить - но можно проще просто изменить длину массива

я конечно нечего не хочу сказать, но моя функция немного меньше операций предлагает, и из за твоей у меня пк подвисает на core i7))
http://learn.javascript.ru/play/feUHP

рони 09.12.2013 18:46

DjDiablo,
3,3,5,6,7,8,9,0,2,9,0,6,0<br>
6,0,3,3,5,6,7,8,9,0,2,9,0<br>
8,9,0,6,0,3,3,5,6,7,2,9,0<br>
5,6,7,8,9,0,6,0,3,3,2,9,0<br>
8,9,0,5,6,7,6,0,3,3,2,9,0<br>
9,0,8,9,0,5,6,7,6,0,3,3,2<br>
3,3,9,0,8,9,0,5,6,7,6,0,2<br>
3,3,9,0,3,8,9,0,5,6,7,6,0,2<br>
3,3,9,0,3,8,9,0,5,6,7,2,6,0,2<br>
3,3,9,0,3,8,9,0,5,6,7,2,8,6,0,2<br>
3,3,9,0,3,8,9,0,5,6,7,2,8,9,6,0,2<br>
3,3,9,0,3,8,9,0,5,6,7,2,8,9,0,6,0,2<br>

Maxmaxmaximus4 09.12.2013 18:51

ш...што вы делаете наркоманы О_О

я уже кстати почти допилил рабочую функцию =) при условии что реплейс приоритетнее, удаления и вставки.
то есть 10 реплейсов, приоритетнее 10 удалений и вставок. а это как раз то что нужно для ui, потому что перерисовать то что есть в уже готовом элементе мне не составит труда

$scope[itemName] = arr[index];
$scope.$digest(); // зарендерить элемент

а вот удалить и создать новый это то же самое что и тут тока новый парсинг дом этого элемента)


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