在特定属性上过滤对象数组的有效方法?

时间:2012-05-09 09:03:11

标签: arrays actionscript-3 flash

我有一组具有不同属性的对象,我需要以不重复特定属性的方式过滤数组。

例如:

var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
                   {foo:"a2", bar:"b2", baz:"c2"},
                   {foo:"a3", bar:"b1", baz:"c3"},
                   {foo:"a1", bar:"b4", baz:"c2"},
                   {foo:"a0", bar:"b3", baz:"c1"}];

现在假设我要过滤属性baz上的对象。过滤数组的最有效方法是什么,以便在操作后没有两个元素具有相同的baz值?

在我的示例中,结果应该只包含:

var result:Array = [{foo:"a1", bar:"b1", baz:"c1"},
                    {foo:"a2", bar:"b2", baz:"c2"},
                    {foo:"a3", bar:"b1", baz:"c3"}]

因为其他对象会有baz属性的重复条目。

结果数组的顺序并不重要,baz具有相同值的那些对象也不会成为结果数组。


更新

对象数组用作数据提供者,用{(1}}填充有关聊天室的信息。数组中的对象携带相关信息(如服务器上的房间ID和其他一些配置设置)。

我在示例中使用的s:Datagrid属性实际上是聊天室配置使用的语言的ID,我想创建一个baz,我可以使用s:DropDownList来过滤Datagrid对于单个语言(例如,显示所有使用"德语")的房间。

很可能有很多具有相同语言ID的对象,但我只希望每个语言ID在DropDownList中显示一次。

我需要从Datagrids's数据提供者(源数组)中提取该信息,并且无法直接检索我的语言,因为DropDownList是许多中使用的泛型DatagridHeaderRenderer的一部分具有不同数据的不同Datagrids

2 个答案:

答案 0 :(得分:2)

private var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
               {foo:"a2", bar:"b2", baz:"c2"},
               {foo:"a3", bar:"b1", baz:"c3"},
               {foo:"a1", bar:"b4", baz:"c2"},
               {foo:"a0", bar:"b3", baz:"c1"}];

private var filteredArray:Array;
private var keys:Object = {};

private function filterArray():void{
    filteredArray = arr.filter(removeDupes);
}

private function removeDupes(item:Object, idx:uint, arr:Array):Boolean {
    if (keys.hasOwnProperty(item.baz)){
        return false;
    } else {
        keys[item.baz] = item;
        return true;
    }
}

private function resetFilter():void{
    filteredArray = new Array();
    keys = {};
}

从多个来源修改,但主要是:http://blog.flexexamples.com/2007/08/05/removing-duplicate-items-from-an-array-using-the-arrayfilter-method/

或者你可以使用arrayCollection及其内置的filterFunction。请参阅:http://cookbooks.adobe.com/post_Using_the_to_ArrayCollection_s_filterFunction-5441.html

答案 1 :(得分:1)

表面看起来应该有效。使用Array.filter通常是在循环中执行相同操作的时间的两倍。

我认为'Dom的removeDupes函数不能完全满足要求,尽管它可能是一种更通用的方法(例如,如果===不是一个好的比较函数,然后这给你一种扩展它的方法。)但是使用hasOwnPropery是一个很大的禁忌。你永远不应该触摸它 - 该功能仅适用于ES兼容性。否则它是邪恶的 - 既是潜在的安全漏洞(因为它在Object.prototype上定义,因此很容易覆盖外部代码)并且很慢(出于同样的原因 - 查找原型上定义的函数是比类中定义的要慢。

    public function Test()
    {
        super();
        var array:Array = [{foo:"a1", bar:"b1", baz:"c1"},
            {foo:"a2", bar:"b2", baz:"c2"},
            {foo:"a3", bar:"b1", baz:"c3"},
            {foo:"a1", bar:"b4", baz:"c2"},
            {foo:"a0", bar:"b3", baz:"c1"}];
        this.removeDuplicates(array, "baz").map(this.objectTracer);
        // { foo : a3, baz : c3, bar : b1 }
        // { foo : a1, baz : c2, bar : b4 }
        // { foo : a0, baz : c1, bar : b3 }
    }

    private function objectTracer(object:Object, index:int, all:Array):void
    {
        var result:String = "";
        for (var p:String in object)
            result += ", " + p + " : " + object[p];
        if (result) result = result.substr(2);
        trace("{ " + result + " }");
    }

    private function removeDuplicates(array:Array, on:String):Array
    {
        var result:Array = array.concat();
        // note that since we use `Dictionary' the 
        // the comparison between objects is the same as `==='
        // if all values are strings, you can use `Object' to
        // save some space.
        var hash:Dictionary = new Dictionary();
        var temp:Object;

        for (var i:int, j:int = result.length - 1; j >= i; j--)
        {
            temp = result[j][on];
            if (temp in hash)
            {
                result[j] = result[i];
                j++; i++;
            }
            else hash[temp] = true;
        }
        // note that we could `shift()` until we get to `i'
        // but when we do it, we actually reallocate the array every time
        // so `slice()' must, in theory, be more efficient
        return result.slice(i);
    }