2010-05-26 2 views
6

У меня есть массив объектов. Каждый объект имеет свойство, называемое именем. Я хочу эффективно удалить объект с определенным именем из массива. Это лучший способ?Более эффективный способ удаления элемента из массива в ActionScript 3

private function RemoveSpoke(Name:String):void { 
    var Temp:Array=new Array; 
    for each (var S:Object in Spokes) { 
     if (S.Name!=Name) { 
     Temp.push(S); 
     } 
    } 
    Spokes=Temp; 
    } 

ответ

12

Если вы готовы потратить некоторую память на справочной таблице это будет довольно быстро:

private function remove(data:Array, objectTable:Object, name:String):void { 
var index:int = data.indexOf(objectTable[name]); 
objectTable[name] = null; 
data.splice(index, 1); 
} 

тест на это выглядит следующим образом:

private function test():void{ 

var lookup:Object = {}; 
var Spokes:Array = []; 
for (var i:int = 0; i < 1000; i++) 
{ 
    var obj:Object = { name: (Math.random()*0xffffff).toString(16), someOtherProperty:"blah" }; 
    if (lookup[ obj.name ] == null) 
    { 
     lookup[ obj.name ] = obj; 
     Spokes.push(obj); 
    } 
} 

var t:int = getTimer(); 
for (var i:int = 0; i < 500; i++) 
{ 
    var test:Object = Spokes[int(Math.random()*Spokes.length)]; 
    remove(Spokes,lookup,test.name) 
} 
trace(getTimer() - t); 

}

+0

Одна важная вещь в этом решении: она будет работать только если каждое «имя» уникально. Если есть несколько объектов с тем же именем, таблица поиска будет терпеть неудачу, по крайней мере, если она построена так. – Quasimondo

+0

интересно ... так что у вас в основном есть два списка с дублирующимися данными ... в общем, было бы лучше просто использовать таблицы поиска и обойтись без массивов для этих ситуаций? работает ли это только потому, что объект имеет свойство 'name' или метод indexOf ищет в каждом свойстве свойства объекта? – mga

+0

Да, если вам не нужен массив для других целей (например, сортировка или доступ к элементам по индексу), в этом случае вы можете просто использовать таблицу поиска. indexOf находит экземпляры объекта. В этом случае для сравнения не используется «имя». Имя используется как хэш в таблице поиска. – Quasimondo

0

Если вы не возражаете, используя ArrayCollection, который является оболочкой для класса Array, вы могли бы сделать что-то вроде этого:

private function RemoveSpoke(Name:String, Spokes:Array):Array{ 
    var ac:ArrayCollection = new ArrayCollection(Spokes); 
    for (var i:int=0, imax:int=ac.length; i<imax; i++) { 
    if (Spokes[i].hasOwnProperty("Name") && Spokes[i].Name === Name) { 
     ac.removeItemAt(i); 
     return ac.source; 
    } 
    } 
    return ac.source; 
} 
+0

FYI ArrayCollection доступен только в Flex – Quasimondo

+1

@Quasimondo: FYI Flex является одним из тегов на вопрос. – Robusto

+0

О, правда, я полностью пропустил это. – Quasimondo

1

У меня нет данных, чтобы поддержать это но я предполагаю, что array.filter может быть самым быстрым.

+1

Если вы имеете в виду что-то вроде этого: var filterName: String = "something"; Spokes = Spokes.filter (function (element: *, index: int, arr: Array): Boolean { \t return (element.name! = FilterName);}); тогда я должен вас разочаровать. Он примерно в 5 раз медленнее, чем у Джоа, и почти на 30 раз медленнее, чем у меня. – Quasimondo

+0

Ха-ха. Вы ребята обманываете! ;) Является ли array.filter хотя бы самым быстрым для методов на основе цикла/итератора? –

5

Самый быстрый путь будет таким:

function remove(array: Array, name: String): void { 
    var n: int = array.length 
    while(--n > -1) { 
    if(name == array[n].name) { 
     array.splice(n, 1) 
     return 
    } 
    } 
} 

remove([{name: "hi"}], "hi") 

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

+0

Joa! Ты жжешь. Но сможет ли Apparat сделать это еще быстрее?:) –

+7

Я позволил себе сравнить ваши «самые быстрые» с моими и прийти с плохими новостями: удаление 500 элементов из массива из 1000 элементов - твой 34 мс, мой 4 мс ;-) – Quasimondo

0

Вы также можете использовать ArrayCollection с filterFunction, чтобы получить вид на тот же объект Array,

0

Он re - эффективная функция с точки зрения повторного использования, позволяющая вам делать больше, чем удалять элемент. Он возвращает индекс, или -1, если не найден.

 
function searchByProp(arr:Array, prop:String, value:Object): int 
{ 
var item:Object; 
var n: int = arr.length; 
for(var i:int=n;i>0;i--) 
{ 
    item = arr[i-1]; 
    if(item.hasOwnProperty(prop)) 
    if(value == item[prop]) 
    return i-1; 
} 
return -1; 
} 
+0

Похоже, что форматирование удалило тип вашего вектора, но я думаю, что это «Объект». Я тестировал его быстро и, по крайней мере, для меня использование Vector в этом случае на самом деле медленнее. Я думаю, что если вы хотите получить прибыль со скоростью Vector, вы также должны использовать реальный тип, а не «Объект». – Quasimondo

+0

Спасибо Quasi. Вы проверили, используя мою функцию? Он имеет дополнительный условный (hasOwnProperty), который замедляет его, но имеет смысл, если вы не уверены, что объект будет иметь свойство. Чтобы ускорить это, удалите это. Но пользователь спросил об эффективности, и эта функция говорит о том, что с точки зрения повторного использования. – reelfernandes

+0

Я протестировал его с предложением Джоа, поэтому hasOwnProperty здесь не проблема. – Quasimondo

1

В целом следует отдавать предпочтение старым для цикла над «для каждого» и «для каждого в» и использовать Вектор, если ваши элементы одного типа. Если производительность действительно важна, вам следует рассмотреть возможность использования связанного списка.

Отправляйте слайды Grant Skinners http://gskinner.com/talks/quick/ и блог Jackson Dunstan за дополнительной информацией об оптимизации.