2010-05-26 47 views
6

我有一個對象數組。每個對象都有一個名爲name的屬性。我想有效地從數組中刪除一個具有特定名稱的對象。這是最好的方式嗎?在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 2010-05-26 21:38:45

+0

有趣......所以你基本上有兩個重複數據的列表......一般來說,只使用查找表並放棄這些情況下的陣列會更好?這是否只是因爲對象具有'name'屬性或者'indexOf'方法在對象的每個屬性值中搜索? – mga 2010-05-26 21:48:29

+0

是的,如果您不需要數組用於其他目的(例如按索引排序或訪問元素),則可以使用查找表。 indexOf查找對象的實例。在這種情況下,它根本不使用「名稱」進行比較。該名稱用作查找表中的散列。 – Quasimondo 2010-05-26 21:51:19

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

僅供參考ArrayCollection僅適用於Flex – Quasimondo 2010-05-26 21:13:42

+1

@Quasimondo:FYI Flex是該問題的標籤之一。 – Robusto 2010-05-26 23:30:45

+0

哦,真的,我完全錯過了那一個。 – Quasimondo 2010-05-27 01:11:23

1

我沒有數據進行備份但我的猜測是array.filter可能是最快的。

+1

如果你的意思是這樣的: var filterName:String =「something」; Spokes = Spokes.filter(function(element:*,index:int,arr:Array):Boolean { \t return(element.name!= filterName);}); 然後我必須讓你失望。它比Joa慢了5倍,比我慢了30倍。 – Quasimondo 2010-05-26 21:24:02

+0

哈哈。你們作弊! ;)對於基於循環/迭代器的方法,array.filter至少是最快的嗎? – 2010-05-26 21:30:45

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的刪除return語句。

+0

Joa!你搖滾。但是Apparat能夠使它更快嗎?:) – 2010-05-26 20:46:25

+7

我允許自己比較你對我的「最快」,並帶來壞消息:從1000個元素陣列中移除500個元素 - 你的34毫秒,我的4ms ;-) – Quasimondo 2010-05-26 21:09:54

0

你也可以使用的ArrayCollection使用的filterFunction得到一個視圖同一數組對象

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 2010-05-26 22:05:51

+0

謝謝準。你用我的功能測試過嗎?它有一個附加的條件(hasOwnProperty),可以減慢它的速度,但如果你不確定該對象是否具有該屬性,則是合理的。爲了更快地消除它。但是用戶詢問效率,而這個功能就可重用性而言就是這樣說的。 – reelfernandes 2010-05-27 16:09:50

+0

我用Joa的建議測試了它,所以hasOwnProperty在這裏不是問題。 – Quasimondo 2010-06-01 18:06:22

1

一般來說,你應該更喜歡舊的for循環結束「每個」和「for each in」,如果元素類型相同,則使用Vector。如果性能非常重要,則應考慮使用鏈接列表。

查看Grant Skinners幻燈片http://gskinner.com/talks/quick/和Jackson Dunstan的博客獲取更多關於優化的信息。

10

myArray.splice(myArray.indexOf(myInstance),1);