2010-05-26 84 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);