开发者

How to find an ArrayCollection item with a specific property value?

开发者 https://www.devze.com 2022-12-08 06:29 出处:网络
I have some XML structures like this: var struct:XML = <mh> <mi id=\"1\" stuff=\"whatever\"/>

I have some XML structures like this:

var struct:XML = <mh>
  <mi id="1" stuff="whatever"/>
  <mi id="2" stuff="whatever"/>
  <mi id="3" stuff="whatever"/>
</mh>;

I know I can access a subnode by "id", in this way:

var stuff:Object = struct.(hasOwnProperty('@id') && @id == '2').@stuff;

Now I have some similar ArrayCollection structure:

private var cmenu:ArrayCollection = new ArrayCollection([
    {id:"1", stuff:"whatever"},
    {id:"2", stuff:"whatever"},开发者_高级运维
    {id:"3", stuff:"whatever"}
]);

I wonder if items can be accessed in a similar way, like this:

var stuff:Object = cmenu['id == 2'].stuff;

Is it possible?


You can generalize Matt's answer a bit so that you can pass in the ID value you want instead of hard-coding it, and only need a single line to get your match (I assume you may want to do this in multiple places).

First you'd write a function to generate your find function:

function findId(id:int):Function {
  return function( element : *, index : int, array : Array ) : Boolean
  {
    return element.id == id;
  }
}

Then I'd write a function to return the first match so you don't have to duplicate the two lines:

function findInCollection(c:ArrayCollection, find:Function):Object {
  var matches : Array = c.source.filter( find );
  return ( matches.length > 0 ? matches[0] : null );
}

Then you'd just do this:

var stuff:String = findInCollection(cmenu, findId(2)) as String;


I've always used filterFunctions for ArrayCollections:

private var cmenu:ArrayCollection = new ArrayCollection([
    {id:"1", stuff:"whatever"},
    {id:"2", stuff:"whatever"},
    {id:"3", stuff:"whatever"}
]);

function getItemFromCollection(id:String):Object {
    var cmenuFiltered:ArrayCollection = new ArrayCollection(cmenu.toArray());

    cmenuFiltered.filterFunction =
        function(item:Object):Boolean {
            return item.id == id;
        }

    cmenuFiltered.refresh();

    return cmenuFiltered.getItemAt(0);
}


No, you can't. struct.mi.(@id == "2").@stuff is E4X which is short for ECMA Script for XML. You can't use e4x on other AS objects.


If you look at the docs for the Array class, you'll find several routines that aid in this, but none as concise as the e4x syntax used by the built-in XML data type. The filter() method in particular sounds like it might be the best fit for your example.

Here's a sample for how you might do this, given your setup.

var matches : Array = cmenu.source.filter( findId2 );
var stuff : Object = ( matches.length > 0 ? matches[0] : null );

...and the callback function findId2:

function findId2( element : *, index : int, array : Array ) : Boolean
{
    return element.id == 2;
}


You can actually go a little bit further and roll the filter function up into the findInCollection function. This means you can just pass the ArrayCollection, property name, and value in the same call:

public function findInCollection(c:ArrayCollection, 
                       propertyName:String, propertyValue:*):Array {

    var matches : Array = c.source.filter( 
               function( element : *, index : int, array : Array ) : Boolean {
                 return element[propertyName] == propertyValue;
               } 
            );

    return matches; 

}

var ac:ArrayCollection=new ArrayCollection(
                [{name:'Ben', id:1, age:12},
                    {name:'Jack', id:2, age:22},
                    {name:'Jill', id:4, age:22},
                    {name:'Joe', id:3, age:17}
                ]
            );
var searchedElements:Array=findInCollection(ac,'age',22);

Returns an array containing the 'Jack' and 'Jill' objects.

Obviously this only works if you are looking for a single property value, but if you wanted to search on multiple properties it would be possible to pass through an object containing the properties and values to search for.


You can even more generalize Herms answer by adding the property name in the function like this and thus getting a rather generic way of searching by property in an ArrayCollection

private function findInCollection(c:ArrayCollection, findFunction:Function):Array
{
 var matches : Array = c.source.filter( findFunction );
 return matches;
}

private function findFunction(propertyName:String,propertyValue:*):Function
{
   return function( element : *, index : int, array : Array ) : Boolean
   {
    return element[propertyName] == propertyValue;
   }
}

with the following usage

var ac:ArrayCollection=new ArrayCollection(
    [{name:'Ben', id:1, age:12},
     {name:'Jack', id:2, age:22},
     {name:'Joe', id:3, age:17}
    ]
);
var searchedElements:Array=findInCollection(ac,findFunction('id',2));

it will return an Array with the following object

{name:'Jack', id:2, age:22}

The drawback of this method is that we hard-code the property name with a String. This may be harmful for code maintenance.


'private var cmenu:ArrayCollection = new ArrayCollection([
    {id:"1", stuff:"whatever"},
    {id:"2", stuff:"whatever"},
    {id:"3", stuff:"whatever"}
]);

for(var i:int=0;i<cmenu.length;i++){
var num:Number=cmenu.getItemAt(i).id;
if(num==2){
var stuf:String=cmenu.getItemAt(i).stuff;
}
}'
0

精彩评论

暂无评论...
验证码 换一张
取 消