2009-10-14 6 views
5

Ho alcune strutture XML come questo:Come trovare una voce ArrayCollection con un valore di proprietà specifico?

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

so di poter accedere ad un sottonodo da "id", in questo modo:

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

Ora ho qualche struttura ArrayCollection simile:

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

mi chiedo se gli elementi si può accedere in modo simile, in questo modo:

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

È possibile?

+0

Tutte le risposte di seguito sono corrette. Non esiste una sintassi magica di hash per i proiettili che è possibile utilizzare per estrarre un oggetto specifico per proprietà, quindi è sufficiente eseguire una serie di cicli per trovare le proprietà. –

+0

Con una coppia di funzioni di aiuto puoi comunque avvicinarti. – Herms

+0

Voglio ringraziarvi per tutte le risposte, so già delle funzioni di supporto ma, dopo tutto, non ho bisogno di usare Object/Array/ArrayCollection ad ogni costo, quindi sono riuscito a convertire tutte quelle cose in xml. –

risposta

3

No, non puoi. struct.mi.(@id == "2")[email protected] è E4X, che è l'abbreviazione di ECMA Script per XML. Non è possibile utilizzare e4x su altri oggetti AS.

+8

Perché non essere utile e mostrare effettivamente all'utente il modo giusto per farlo, piuttosto che semplicemente dire "No, non puoi"? –

+1

Quando ho visto questo thread, c'erano risposte che spiegavano come farlo - perché dovrei farlo di nuovo? Ma ho pensato che sarebbe stato utile far sapere a OP perché "@syntax" non era possibile su collezioni di array e altri oggetti AS in generale. E apparentemente OP stava "chiedendosi se gli oggetti possono essere acceduti in un modo simile" - così un "no" e "perché no" sembravano una buona risposta. – Amarghosh

3

Se si esaminano i documenti per la classe Array, sono disponibili diverse routine che aiutano in questo, ma nessuna sintonia concisa come la sintassi e4x utilizzata dal tipo di dati XML incorporato. Il metodo filter() in particolare suona come potrebbe essere la soluzione migliore per il tuo esempio.

Ecco un esempio di come si potrebbe fare ciò, data la configurazione.

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

... e il callback funzione di findId2:

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

ho sempre usato per filterFunctions 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); 
} 
18

Si può generalizzare la risposta di Matt un po 'in modo da poter passare il valore ID che si desidera invece di codificarlo e basta una sola riga per ottenere la corrispondenza (presumo che si desideri eseguire questa operazione in più punti).

In primo luogo ci si scrivere una funzione per generare la vostra funzione di ricerca:

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

Poi mi piacerebbe scrivere una funzione per restituire la prima partita in modo non c'è bisogno di duplicare le due linee:

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

Poi devi solo fare questo:

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

Wow, uso pulito di quella fabbrica di funzioni. Ho sempre pensato che ci fosse un modo per personalizzare la routine di callback; questo è davvero elegante –

+0

Questo è stato molto utile per me dal momento che le Collezioni di Array non sono così semplici in Flex/AS3 come in altre lingue. Grazie a @Herms per la tua soluzione semplice su questo. Lo sto usando per un servizio XML con file locale. – Pimenta

+1

Molto utile e molto veloce su grandi collezioni! Grazie mille! – tigeryan

0

È possibile ancora più generalizzare Herms risposta aggiungendo il nome della proprietà nella funzione come questo e ottenendo così un modo piuttosto generico di ricerca per proprietà in un 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; 
    } 
} 

con il seguente utilizzo

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)); 

restituirà un array con il seguente oggetto

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

Lo svantaggio di questo metodo è che codifichiamo il nome della proprietà con una stringa. Ciò potrebbe essere dannoso per la manutenzione del codice.

2

Si può effettivamente andare un po 'oltre e ruotare la funzione del filtro verso l'alto nella funzione findInCollection. Questo significa che si può semplicemente passare l'ArrayCollection, nome della proprietà, e il valore nella stessa chiamata:

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); 

restituisce un array contenente il 'Jack' e oggetti 'Jill'.

Ovviamente questo funziona solo se si sta cercando un singolo valore di proprietà, ma se si desidera eseguire la ricerca su più proprietà, sarebbe possibile passare attraverso un oggetto contenente proprietà e valori da cercare.

0
'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; 
} 
}' 
Problemi correlati