#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;
}