views:

2045

answers:

7

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?

+2  A: 

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;
}
Matt Dillard
+2  A: 

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);
}
Eric Belair
+4  A: 

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;
Herms
Wow, neat use of that function factory. I've always felt there must be a way to customize the callback routine; this is really elegant.
Matt Dillard
+2  A: 

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.

Amarghosh
Why not be helpful, and actually show the user the right way to do it, rather than simply telling them "No, you can't"?
Eric Belair
When I saw this thread, there were answers explaining how to do it - why would I do that again? But I thought it would be good to let OP know why the "@syntax" was not possible on array collections and other AS objects in general. And apparently OP was "wondering if items can be accessed in a similar way" - so a "no" along with "why not" seemed a good answer.
Amarghosh
A: 

Hi,

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.

tit
A: 

Why not use cursors?

johans
can you explain please?
Giorgio Gelardi
A: 

I use the line of code below to pass the data values for geocoding, and it works fine: var myAddress:Array = { id:1, address:"125 W Vine St",city:"Redlands", state:"California", zip:"92373" };

For general application, I try the code in Post 0 and Post 1. First, I created an ArrayCollection:

addressData = new ArrayCollection(); addressData.addItem ( { id:0, address:"380 New York St",city:"Redlands", state:"California", zip:"92373" }); addressData.addItem ( { id:1, address:"125 W Vine St",city:"Redlands", state:"California", zip:"92373" });

Then, I wrote another 2 lines of code: var arrTemp:Array = findInCollection(addressData, findFunction('id', 0)); myAddress = { id:arrTemp.id, address:arrTemp.address, city:arrTemp.city, state:arrTemp.state, zip:arrTemp.zip }; It does not work. What is wrong with my coding? Thanks.

mrgis