Alexander Farber
Alexander Farber

Reputation: 23038

Counting elements in JSON array, which is in an Object

I have a pure ActionScript 3 problem, but the simplified test case I've prepared is in Flex 4 for better visibility (the source code is below):

enter image description here

Since Flash Player 11 / AIR 3 support JSON natively, I've decided to move a multiplayer game, which used XML for communicating with server, to JSON.

But I have a frustrating problem, that given two Objects like

                { 9013: [
                    "OK305894249541",
                    "OK151358069597",
                    "OK515549948434",
                ] },
                { 8991: [
                    "OK253525117889",
                    "OK529081480134",
                ] },

I don't know how to create an ActionScript function, which would report 3 for the first Object and 2 for the second Object?

The "9013" and "8991" in the example above are game numbers.

The "OKxxxx" strings represent players.

A game is "full" when it holds 3 players, "vacant" otherwise.

Here is my very simple TestCase.mxml:

<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    creationComplete="init(event)">

    <fx:Declarations>
        <s:RadioButtonGroup id="_filter" change="handleRadio(event);" />
    </fx:Declarations>

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;

            [Bindable]
            private var _games:ArrayCollection = new ArrayCollection();

            [Bindable]
            private var _all:uint = 0;

            [Bindable]
            private var _vac:uint = 0;

            [Bindable]
            private var _full:uint = 0;

            private function vacantGame(obj:Object):Boolean {
                // XXX how to implement?
                // XXX return true if obj has less than 3 players
                return true;
            }

            private function fullGame(item:Object):Boolean {
                // XXX how to implement?
                // XXX return true if obj has exactly 3 players
                return true;
            }

            private function init(event:FlexEvent):void {
                var i:uint;

                _games.source = OBJ['games'];

                _all = _games.length;

                _vac = 0;
                for (i = 0; i < _games.length; i++)
                    if (vacantGame(_games[i]))
                        _vac++;

                _full = 0;
                for (i = 0; i < _games.length; i++)
                    if (fullGame(_games[i]))
                        _full++;
            }

            private function handleRadio(event:Event):void {
                switch (_filter.selection) {
                    case _allBtn:
                        _games.filterFunction = null; 
                        break;
                    case _vacBtn:
                        _games.filterFunction = vacantGame;
                        break;
                    case _fullBtn:
                        _games.filterFunction = fullGame;
                        break;
                }
                _games.refresh();
            }

            private const OBJ:Object = {
                lobby: [
                    "OK108900197210",
                    "OK266559712237",
                    "DE6577",
                    "DE7981",
                    "OK225312168135",
                    "OK20629248715",
                    "DE7880",
                ],
                games: [
                    { 0: [] },
                    { 9012: [
                        "VK48058967",
                        "MR14315189992643135976",
                        "OK10218913103",
                    ] },
                    { 9013: [
                        "OK305894249541",
                        "OK151358069597",
                        "OK515549948434",
                    ] },
                    { 8991: [
                        "OK253525117889",
                        "OK529081480134",
                    ] },
                    { 8937: [
                        "OK304672497140",
                        "VK90145027",
                        "OK338360548262",
                    ] },
                    { 9005: [
                        "OK40798070412",
                        "DE7979",
                        "OK531589632132",
                    ] },
                    { 9010: [
                        "OK357833936215",
                    ] },
                ]
            };
        ]]>
    </fx:Script>

    <s:HGroup verticalAlign="baseline">
        <s:Label text="Games:" />
        <s:RadioButton id="_allBtn" group="{_filter}" label="All: {_all}" selected="true" />
        <s:RadioButton id="_vacBtn" group="{_filter}" label="Vacant: {_vac}" />
        <s:RadioButton id="_fullBtn" group="{_filter}" label="Full: {_full}" />
    </s:HGroup>
</s:Application>

Upvotes: 0

Views: 1078

Answers (1)

Creynders
Creynders

Reputation: 4583

The right answer is to rethink your data structure. Drop the surrounding array, all games have a unique ID anyway.

But if you insist on using it as above, you can do the following:

private function vacantGame(obj:Object):Boolean{
    for( var gameNumber : String in obj ){
        var players : Array = obj[ gameNumber ]
        return players.length < 3
    }
    return false;
}

The better way:

games: {
    0: [],
    9012: [
        "VK48058967",
        "MR14315189992643135976",
        "OK10218913103",
    ],
    9013: [
        "OK305894249541",
        "OK151358069597",
        "OK515549948434",
    ],
    ...
}

then

for( var gameNumber : String in OBJ.games ){
    var players : Array = OBJ.games[ gameNumber ];
    if( players.length < 3 ){
        //vacant
    }else{
        //full
    }
}

Upvotes: 1

Related Questions