2015-01-01 3 views
0

Если у меня есть многомерный массив вроде: [[a,b],[a,c],[b,a],[b,c],[c,a],[c,b]], как я могу пройти и удалить повторы, где [a,b] - это то же самое, что и [b,a].Javascript arrays ab = ba

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

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

+0

возможно дубликат [Удалить дубликаты из массива JavaScript] (http://stackoverflow.com/questions/9229645/remove-duplicates-from-javascript-array) - второй ответ здесь под заголовком «Unique By» должен помочь – Rhumborl

+0

@Rhumborl нет, это не дубликат этого вопроса. Он не хочет удалять записи, которые появляются несколько раз, он просто хочет отфильтровать некоторые записи на основе описанных критериев. – Pointy

+2

Не совсем ясно, какое значение имеет значение «a», «b» и т. Д., Повторяющееся в вашем примере. Все, что я могу сказать наверняка, это то, что вы не хотите кортежей, где первый элемент совпадает с вторым элементом. – Pointy

ответ

1

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

Прежде всего, почему бы нам не воспользоваться хэш-ориентированной природой массивов и объектов javascript? Мы могли бы создать объект, содержащий отношения (для создания своего рода карты) и сохранить в новом массиве те отношения, которые еще не были сохранены. При таком подходе нет проблем и с объектами, мы просто запрашиваем идентификатор или хэш или что-то еще для каждого объекта. Этот идентификатор должен сделать связь между ними возможной.

ОБНОВЛЕНИЕ

  • Скрипт теперь контролирует возможность повторных элементов Fe [[а, Ь], [а, Ь]]
  • Скрипт теперь контролирует возможность элементов с таким же объект повторяется f.е [[а, а], [а, а] [а, а]] вернется [а, а]

Код:

var temp = {}, 
    massive_arr = [['a','b'],['a','c'],['a','d'], ['b','a'],['b','c'],['b','d'],['c','a'],['c','b'],['c','d']], 
    final_arr = [], 
    i = 0, 
    id1, 
    id2; 
for(; i < massive_arr.length; i++) { 
    id0 = objectIdentifier(massive_arr[i][0]);// Identifier of first object 
    id1 = objectIdentifier(massive_arr[i][1]);// Identifier of second object 

    if(!temp[id0]) {// If the attribute doesn't exist in the temporary object, we create it. 
     temp[id0] = {}; 
     temp[id0][id1] = 1; 
    } else {// if it exists, we add the new key. 
     temp[id0][id1] = 1; 
    } 

    if(id0 === id1 && !temp[id0][id1+"_bis"]) {// Especial case [a,a] 
     temp[id0][id1+"_bis"] = 1; 
     final_arr.push(massive_arr[i]); 
     continue;// Jump to next iteration 
    } 

    if (!temp[id1]) {// Store element and mark it as stored. 
     temp[id1] = {}; 
     temp[id1][id0] = 1; 
     final_arr.push(massive_arr[i]); 
     continue;// Jump to next iteration 
    } 

    if (!temp[id1][id0]) {// Store element and mark it as stored. 
     temp[id1][id0] = 1; 
     final_arr.push(massive_arr[i]); 
    } 
} 
console.log(final_arr); 

function objectIdentifier(obj) { 
    return obj;// You must return a valid identifier for the object. For instance, obj.id or obj.hashMap... whatever that identifies it unequivocally. 
} 

Вы можете проверить это here

ВТОРОЙ ОБНОВЛЕНИЕ

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

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

var temp = {}, 
massive_arr = [ 
    ['a', 'a', 'a'], //0 
    ['a', 'a', 'b'], //1 
    ['a', 'b', 'a'], 
    ['a', 'a', 'b'], 
    ['a', 'c', 'b'], //2 
    ['a', 'c', 'd'], //3 
    ['b', 'b', 'c'], //4 
    ['b', 'b', 'b'], //5 
    ['b', 'b', 'b'], 
    ['b', 'c', 'b'], 
    ['b', 'c', 'd'], //6 
    ['b', 'd', 'a'], //7 
    ['c', 'd', 'b'], 
    ['c', 'a', 'c'], //8 
    ['c', 'c', 'a'], 
    ['c', 'd', 'a', 'j'], // 9 
    ['c', 'd', 'a', 'j', 'k'], // 10 
    ['c', 'd', 'a', 'o'], //11 
    ['c', 'd', 'a'] 
], 
    final_arr = [], 
    i = 0, 
    j, 
    ord, 
    key; 
for (; i < massive_arr.length; i++) { 
    ord = []; 
    for (j = 0; j < massive_arr[i].length; j++) { 
     ord.push(objectIdentifier(massive_arr[i][j])); 
    } 

    ord.sort(); 
    key = ord.toString(); 

    if (!temp[key]) { 
     temp[key] = 1; 
     final_arr.push(massive_arr[i]); 
    } 
} 

console.log(final_arr); 

function objectIdentifier(obj) { 
    return obj; 
} 

Это может быть проверено here

+0

Я havent попробовал его с объектами, но похоже, что он должен работать. Примите как ответ, как только я попытаюсь его реализовать. –

+0

@MatthewMartini Спасибо, пожалуйста, дайте мне знать, если это сработает, мне это интересно. BTW, теперь он проверяет, есть ли повторяющиеся элементы и только один раз хранит их. Например, [[a, b], [a, b]] будет хранить [a, b] только один раз. Надеюсь, поможет. – acontell

+0

Работает отлично, не тестировалось, но работает очень быстро с наборами до 1000 пока. Проблема в том, что если я добавляю третий элемент к каждому подмассиву. просто добавление 'temp [id2]' явно не является решением. я буду продолжать пытаться понять, есть ли способ использовать субариры длины 'n', а не только 2. –

1

Основываясь на моем понимании того, что вы хотите удалить из исходного массива любых детей массивы, которые занимают один и тот же набор объектов, без учета того, этот должен сделать это некоторый код:

function getId(obj) { // apparently these objects have identifiers 
    return obj._id; // I'm testing with MongoDB documents 
} 
function arraysEqual(a, b) { 
    if (a === b) { return true; } 
    if (a == null || b == null) { return false; } 
    if (a.length != b.length) { return false; } 
    aIds = []; bIds = []; 
    for (var i = 0; i < a.length; i++) { 
    aIds.push(getId(a[i])); bIds.push(getId(b[i])); 
    } 
    aIds.sort(); bIds.sort(); 
    for (var i = 0; i < aIds.length; i++) { 
    if(aIds[i] !== bIds[i]) { return false; } 
    } 
    return true; 
} 
function removeRepeats(list) { 
    var i, j; 
    for (i=0; i < list.length; i++) { 
    for (j=i+1; j < list.length; j++) { 
     if (arraysEqual(list[i], list[j])) { 
     list.splice(j,1); 
     } 
    } 
    } 
} 

removeRepeats функция проходит через каждый элемент и сравнивает ее с каждым элементом, который приходит после него. arraysEqual function simply returns true if the arrays are equal. isEquivalent function должен проверить эквивалентность объекта. Как отмечено на этой веб-странице, существуют библиотеки, проверяющие эквивалентность объектов. Если вы можете добавить эти библиотеки, вы можете заменить функцию isEquivalent на _.isEqual.

+0

не точный ответ, но я не знаю, если он еще не прав, я играю с ним, чтобы посмотреть, смогу ли я сделать эту работу. Поскольку он стоит, 'arraysEqual' всегда возвращает false, а' removeRepeats' всегда возвращает undefined. Есть ли что-то, что особенно непонятно в вопросе? –

+0

Функция 'arraysEqual()' может возвращать 'false' все время, потому что никакие два объекта не равны друг другу. Если, например, массив начался как JSON, тогда каждое значение будет отличаться и не будет '===' любым другим значением, независимо от того, как выглядят объекты. – Pointy

+0

(ОП разъяснил в комментарии по вопросу о том, что фактически используемые значения являются объектами.) – Pointy

0
*** 
* Turns out the OP has objects in his list, so this approach won't 
* work in that case. I'll leave this for future reference. 
*** 

var foo = [['a','b'],['a','c'],['b','a'],['b','c'],['c','a'],['c','b']]; 

function removeRepeats(list) { 
    var i; 
    var b = []; 
    var _c = []; 

    for (i = 0; i < list.length; i++) { 
     var a = list[i].sort(); 
     var stra = a.join("-"); 

     if(_c.indexOf(stra) === -1) { 
      b.push(a); 
      _c.push(stra); 
     } 
    } 

    return b; 
} 

console.log(removeRepeats(foo)); 

Это не самый красивый код, который я когда-либо производил, но этого должно быть достаточно, чтобы вы начали. Я думаю. Что я делаю, так это создание двух новых массивов, b и _c. b будет массивом без повторов. _c - это вспомогательный массив, который содержит все уникальные пары, уже обработанные в виде строки, поэтому я могу выполнять простые сравнения строк при прохождении через list.

+1

Я предлагаю вам попробовать это на стартовом массиве «foo», содержащем записи «много десятков тысяч». Каждый из этих вызовов '.indexOf()' будет занимать больше времени и дольше (предполагая, что массив не начинается с почти всех дубликатов). – Pointy

+0

Его можно легко заменить на 'for' (красный: он сказал' while' раньше, но при этом получается, что производительность еще хуже, см. Ссылку ниже), если производительность оказывается неприемлемой. – Bjorn

+0

Цикл 'while' будет страдать от одной и той же проблемы; это алгоритмическая проблема. – Pointy

Смежные вопросы