Flash as3 Как удалить дубликаты в массиве? - PullRequest
5 голосов
/ 14 мая 2011

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

Ответы [ 9 ]

18 голосов
/ 14 мая 2011

много способов.Вы можете сортировать массив и перебирать его, игнорируя записи, соответствующие предыдущей итерации.Или вы можете использовать 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);
5 голосов
/ 14 мая 2011

Больше шкуры кошки:

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 && a[i] == a[i+1]) {
        a.splice(i, 1);
    }
    i++;
}
4 голосов
/ 07 августа 2012

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

Я проверил некоторые из них, и они имеют худшие результаты в отличие от моих.Пример:

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: 8946ms, 8718ms, 8936ms

Подход Obj: 8800ms, 8809ms, 8769ms

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

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


Обновление 02 / июль / 2019

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

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

3 голосов
/ 14 мая 2011

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

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 голос
/ 21 июня 2018

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

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);
    });
1 голос
/ 18 июля 2012

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

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

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

1 голос
/ 14 мая 2011

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

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 && item !== other && 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, вероятно, гораздо более эффективен, но это теория, которую вы просили:)

0 голосов
/ 28 декабря 2018
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;
}
0 голосов
/ 28 февраля 2012

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

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

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...