Flash as3 Как мне удалить дубликаты в массиве?

#flash #actionscript-3 #actionscript

#flash #actionscript-3 #actionscript

Вопрос:

Привет, у меня просто есть массив имен (строк) во flash, и я хочу убедиться, что все дубликаты из массива удалены или, по крайней мере, что функция выполняется только один раз для каждого повторно возвращаемого значения в массиве.

Ответ №1:

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

Вот способ по словарю, стоимость памяти составляет 1 логическое значение за уникальную запись, это удобно для памяти, когда вы ожидаете много дубликатов, и быстро. Если у вас относительно мало дубликатов, сортировка отбраковка последовательных дубликатов, вероятно, более эффективна

 import flash.utils.Dictionary;

var array:Array = ["harry","potter","ron","harry","snape","ginny","ron"];
var dict:Dictionary = new Dictionary();

for (var i:int = array.length-1; i>=0; --i)
{
    var str:String = array[i] as String;
    trace(str);
    if (!dict[str])
    {
        dict[str] = true;
    }
    else
    {
        array.splice(i,1);
    }
}

dict = null;


trace(array);
  

Вот способ сортировки, но обратите внимание: ЭТО НЕ СОХРАНЯЕТ ПОРЯДОК! Вы не сказали, имеет ли это значение. Но поскольку он использует быструю сортировку, он, как правило, имеет производительность O (N log N) плюс один дополнительный проход, если, конечно, ваши данные не являются патологическим случаем.

 var array:Array = ["harry","potter","ron","harry","ron","snape","ginny","ron"];

array.sort();
trace(array);

for (var i:int = array.length-1; i>0; --i)
{
    if (array[i]===array[i-1])
    {
        array.splice(i,1);
    }
}


trace(array);
  

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

 import flash.utils.Dictionary;

var array:Array = ["harry","potter","ron","harry","snape","ginny","ron"];
var dict:Dictionary = new Dictionary();

var len:int = array.length;
for (var i:int = 0; i<len;   i)
{
    var str:String = array[i] as String;
    if (!dict[str])
    {
        dict[str] = true;
    }
    else
    {
        array.splice(i,1);
        i--; len--;
    }
}

dict = null;


trace(array);
  

Ответ №2:

Еще одна очистка от кошек:

 var a:Array = ["Tom", "John", "Susan", "Marie", "Tom", "John", "Tom", "Eva"];
a.sort();
var i:int = 0;
while(i < a.length) {
    while(i < a.length 1 amp;amp; a[i] == a[i 1]) {
        a.splice(i, 1);
    }
    i  ;
}
  

Ответ №3:

Хорошие ответы!

Я проверил несколько из них, и у них результаты хуже, чем у меня. Пример:

 const origin: Vector.<String> = Vector.<String>(["a", "c", "d", "c", "b", "a", "e", "b", "a"]);

function getUniqueVector(origin: Vector.<String>): Vector.<String> {
    const n: uint = origin.length;
    var res: Vector.<String> = new Vector.<String>();
    var i: int = 0;

    while(i < n) {
        var el: String = origin[i];
        if(res.indexOf(el) == -1) res.push(el);
        i  = 1;
    }

    return res;
}

trace(getUniqueVector(origin)); // unique elements vector
  

Статистика с моими данными:

Подход Dict: 8946 мс, 8718 мс, 8936 мс

Obj-подход: 8800 мс, 8809 мс, 8769 мс

Мой старый подход: 8723 мс, 8599 мс, 8700 мс

Этот подход: 6771 мс, 6867 мс, 6706 мс


Обновление 02 / ИЮЛЬ / 2019

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

Но Flash мертв, и, вероятно, ActionScript, так что это была похоронная речь : (

Комментарии:

1. Хороший ответ! Что касается вашего комментария, вы слышали об Apache Royal ? Король мертв, да здравствует королевский!

Ответ №4:

Это один из способов сделать это, я уверен, что есть и другие.

 function removeDuplicate(sourceArray:Array) : void
{
    for (var i:int = 0; i < sourceArray.length - 1; i  )
    {
        for (var j:int = i   1; j < sourceArray.length; j  )
        {
                if (sourceArray[i] === sourceArray[j])
                {   
                     // Remove duplicated element and decrease j index.
                     sourceArray.splice(j--, 1);
                }
        }
    }
}
  

Комментарии:

1. Это можно было бы сделать на месте, но это очень расточительно с точки зрения временной сложности, а не лучшее решение. Существует множество способов сделать это, которые не являются O (N ^ 2). То, какое именно решение оптимально для реальных данных, немного зависит от ожидаемой частоты дубликатов.

2. да, согласен. Просто даю ему концепцию для работы. В любой ситуации вы можете выбрать другой hammer.

3. Но, я думаю, руководство по всем потенциальным hammers и их плюсам и минусам, может быть полезным. Впрочем, я пока обойдусь без этого.

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

Ответ №5:

Вот другой способ сделать это, возможно, немного более приятный на вид:

 var removeList:Array = [];

// loop over every item in the original array
for each (var item:* in array) {
    // loop over every item again, checking for duplicates
    for each (var other:* in array) {
        // if two items that aren't the same item are equal and `other` doesn't
        // exist in the remove list, then cache it for later removal.
        if (item == other amp;amp; item !== other amp;amp; removeList.indexOf(other) == -1)
            removeList.push(other);
    }
}

// next, loop over the cached remove list and remove 'selected' items for removal
for each (var remove:* in removeList) 
    array.splice(array.indexOf(remove), 1);
  

Вероятно, это не самый эффективный способ сделать это, метод @prototypical, вероятно, намного эффективнее, но это теория, о которой вы просили 🙂

Ответ №6:

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

   for (var i:uint = array.length; i > 0; i--){
     if (array.indexOf(array[i-1]) != i-1){
        array.splice(i-1,1);
     }
  }     
  

Идея здесь в том, что вы выполняете цикл в обратном порядке по массиву, и поскольку indexOf выдает вам первый встречающийся индекс, вы можете сверить найденный индекс с текущим индексом (i) и удалить, если он не совпадает.

Ответ №7:

Вот более элегантный способ удаления дубликатов:

 var items:Vector.<String> = Vector.<String>(['tortoise', 'cat', 'dog', 'bunny', 'dog', 'cat', 'bunny', 'lion']);

var uniqueItems:Vector.<String> = items.filter(function(item:String, index:int, vector:Vector.<String>):Boolean {
    return index==0?true:(vector.lastIndexOf(item, index-1) == -1);
});
  

Тот же подход для массива:

 var items:Array = ['tortoise', 'cat', 'dog', 'bunny', 'dog', 'cat', 'bunny', 'lion'];

var uniqueItems:Array = items.filter(function(item:String, index:int, array:Array):Boolean {
        return index==0?true:(array.lastIndexOf(item, index-1) == -1);
    });
  

Ответ №8:

не вызовет ли ответ @prototypical s проблем, если sourceArray [i] совпадает с sourceArray [j] более одного раза, потому что длина sourceArray была бы короче, если бы элемент был .splice()удален из него?

Я переписал этот метод, чтобы считать с конца, чтобы этого не происходило

 for (var i:int = sourceArray.length - 2; i >= 0; --i) 
{
    for (var j:int = sourceArray.length - 1; j > i; --j)
    {
        trace(i, j);
        if (sourceArray[j] === sourceArray[i]) sourceArray.splice(j, 1);
    }
}
  

Ответ №9:

 function removeDuplicateElement(_arr:Array):Array{
   //set new Dictionary
   var lDic:Dictionary = new Dictionary();
   for each(var thisElement:* in _arr){
      //All values of duplicate entries will be overwritten
      lDic[thisElement] = true;
   }
   _arr = [];
   for(var lKey:* in lDic){
     _arr.push(lKey);
  }
  return _arr;
}