1

I have an array that looks like this:

Array(
[0] => Array([city] => 309[store] => 12[apples] => 21[oranges] => 14[lichis] => 34)
[1] => Array([city] => 309[store] => 13[apples] => 0[oranges] => 11[lichis] => 32)
[2] => Array([city] => 309[store] => 14[apples] => 44[oranges] => 61[lichis] => 0)
[3] => Array([city] => 309[store] => 15[apples] => 7[oranges] => 0[lichis] => 6)
[4] => Array([city] => 309[store] => 16[apples] => 0[oranges] => 0[lichis] => 12) )

There's two things I need to do here:
1. get the count of all the specific fruits in the city (i.e. how many apples, oranges, lichies are there in total in city 309) and
2. How do I grab the values for a specific store?

Thanks in advance!

3
  • Do you mean sum of fruits for each city ? Commented Jan 8, 2013 at 14:35
  • Create array of infinite fruits in infinite cities. Then merely subtract cities and fruits not found. Commented Jan 8, 2013 at 14:50
  • I strongly recommend you to use classes and custom methods instead of dealing with plain arrays. That way you can filter out whatever you like. Commented Jan 8, 2013 at 20:11

4 Answers 4

2

ok say the array is called $store

$count = 0;
$s = array();

foreach($store as $store){
 $count = 0;
 $count += $store['apples'];
 $count += $store['oranges'];

 $s[$store['store']] = $count;
}

add more fruit if needed.

Sign up to request clarification or add additional context in comments.

1 Comment

Upvote. much better than my idea of an infinite cities/fruits array.
0

This is a more complicated example, but better than spaghetti code. Turn your array into XML first.

// this is your initial array
$my_array = array(
array("city"=>309, "store"=>12, "apples"=>21, "oranges"=>14, "lichis"=>34 ),
array("city"=>309, "store"=>13, "apples"=>0, "oranges"=>11, "lichis"=>32 ),
array("city"=>309, "store"=>14, "apples"=>44, "oranges"=>61, "lichis"=>0 ),
array("city"=>309, "store"=>15, "apples"=>7, "oranges"=>0, "lichis"=>6 ),
array("city"=>309, "store"=>16, "apples"=>0, "oranges"=>0, "lichis"=>12 ),
);

Writing spaghetti code to manually isolate stores becomes a messy jungle of if statements and loops.

// might as well convert it to xml
function array_to_xml( $data ) {
    $xml = "<xml>\n";
    foreach( $data as $row ) {
        $xml .= "<entry>";
        foreach( $row as $k => $v ) {
            $xml .= "<{$k}>{$v}</{$k}>";
        }
        $xml .= "</entry>\n";
    }
    $xml .= "</xml>\n";
    return( $xml );
}

At this point, $xml looks like this (as a string) and is more manageable:

<xml>
  <entry>
    <city>309</city>
    <store>12</store>
    <apples>21</apples>
    <oranges>14</oranges>
    <lichis>34</lichis>
  </entry>
  ...(more entries)...
</xml>

Now, load it into something queriable with XPath, an XML standard:

$xml = simplexml_load_string( array_to_xml( $my_array ) );

To get the count of all the specific fruits in the city (i.e. how many apples, oranges, lichies are there in total in city 309) we need a simple but reusable summary function.

// so lets make a generic function to count specific items
function count_items( $stores, $items = array() ) {
    $sum = array();
    foreach( $stores as $store ) {
        foreach( $items as $k ) {
            if( !isset( $sum[$k] ) ) $sum[$k] = 0;
            $sum[$k] += $store->$k;
        }
    }
    return( $sum );
}

We only want city 309, and looking specifically for apples, oranges and lichis, since they are fruits:

$only_this_city = $xml->xpath("//entry[city=309]");
print_r( count_items( $only_this_city, array("apples", "oranges", "lichis")) );

We get this:

Array
(
    [apples] => 72
    [oranges] => 86
    [lichis] => 84
)

Secondly, to grab the values for a specific store:

$only_this_store = $xml->xpath("//entry[city=309 and store=14]");
print_r( count_items( $only_this_store, array("apples") ) );

You get:

Array
(
    [apples] => 44
)

Obviously you can request more items, or query with more complexity. Look up some docs on XPath for future queries.

3 Comments

Such a large supporting structure. I would rather write some spaghetti code with self-explaining element names and plenty of comments. I'm tempted to down-vote; but of course, the OP does not say what the real needs are, and if they are intensive, then a robust solution is the best. Also, it's much better than the infinite cities/fruits array suggestion.
Appreciate the comment and restraint, but I wasn't trolling - was being verbose deliberately to point out that sometimes you should focus on code maintenance and reusability instead of the immediate task at hand. IMO, it takes a complex example to point that there are additional benefits to using standardized query methods like XPath.
Points are well presented and intriguing. "Trolling" never crossed my mind (except maybe concerning my own behavior).
0
function extractData( array $data, $store = null )
{
    $callback = function( $values, $array ) use ( $store )
    {
        // We require values for a particular store
        if( ! is_null( $store ) )
        {
            if( $array[ 'store' ] == $store )
            {
                return $array;
            }

            return false;
        }
        // Return the sum of all stores in a city
        else
        {
            // Toss out the city and store values since they're not needed
            unset( $array['city'], $array['store'] );

            // Seed the initial values
            if( ! is_array( $values ) || empty( $values ) )
            {
                return $array;
            }

            // array_map function used add the arrays
            $add = function( $a, $b )
            {
                return $a + $b;
            };

            // Add the arrays
            $summedArray = array_map( $add, $values, $array );

            // Return the combined array structure
            return array_combine( array_keys( $values ), $summedArray );
        }
    };

    return array_reduce( $data, $callback, array() );
}

$data = array(
    0 => array(
        "city" => 309,
        "store" => 12,
        "apples" => 21,
        "oranges" => 14,
        "lichis" => 34
    ),
    1 => array(
        "city" => 309,
        "store" => 13,
        "apples" => 0,
        "oranges" => 11,
        "lichis" => 32
    ),
    2 => array(
        "city" => 309,
        "store" => 14,
        "apples" => 44,
        "oranges" => 61,
        "lichis" => 0
    ),
    3 => array(
        "city" => 309,
        "store" => 15,
        "apples" => 7,
        "oranges" => 0,
        "lichis" => 6
    ),
    4 => array(
        "city" => 309,
        "store" => 16,
        "apples" => 0,
        "oranges" => 0,
        "lichis" => 12
    )
);

// Return the values for a particular store
print_r( extractData( $data, 16 ) );

// Return the total of all stores in the city
print_r( extractData( $data ) );

Which would yield the following results...

Single City

Array
(
    [city] => 309
    [store] => 16
    [apples] => 0
    [oranges] => 0
    [lichis] => 12
)

Totals

Array
(
    [apples] => 72
    [oranges] => 86
    [lichis] => 84
)

Comments

0

NOTE: Before any reaction… I know the OP has not asked how to handle this in an object-oriented fashion so this is just a suggestion.

I would create a separate class for the overall data and another for each store data.

$arr = array(
    array('city' => 309, 'store' => 12, 'apples' => 21, 'oranges' => 14, 'lichis' => 34),
    array('city' => 309, 'store' => 13, 'apples' => 0, 'oranges' => 11, 'lichis' => 32),
    array('city' => 309, 'store' => 14, 'apples' => 44, 'oranges' => 61, 'lichis' => 0),
    array('city' => 309, 'store' => 15, 'apples' => 7, 'oranges' => 0, 'lichis' => 6),
    array('city' => 309, 'store' => 16, 'apples' => 0, 'oranges' => 0, 'lichis' => 12)
);

foreach ($arr as $rec) {
    $storeID = $rec['store'];
    $city = $rec['city'];
    unset($rec['city'],$rec['store']);
    // assuming all the keys except these 2
    // represent product name->quantity pairs
    StoreData::add(new Store($storeID,$city,$rec));
}
//print_r(StoreData::$stores);

echo
'<b>total products:</b> ' .
    StoreData::get_total_products() . PHP_EOL .
'<b>total products in city #309:</b> ' .
    StoreData::get_total_products_by_city(309) . PHP_EOL .
'<b>"apples" everywhere:</b> ' .
    StoreData::get_product_total('apples') . PHP_EOL .
'<b>"apples" in store #12:</b> ' .
    StoreData::get_product_total_by_store('apples',12) . PHP_EOL .
'<b>"apples" in city #309:</b> ' .
    StoreData::get_product_total_by_city('apples',309);


class StoreData {

    public static $stores = array();

    public static function add(Store $store) {
        self::$stores[] = $store;
    }

    public static function remove(Store $store) {
        foreach (self::$stores as $key => $value) {
            if ($value == $store) {
                unset(self::$stores[$key]);
                break;
            }
        }
    }

    public static function find_by_city($cityID) {
        $cityID = (int) $cityID;
        return array_filter(self::$stores,create_function(
            '$store',
            "return \$store->city == $cityID;")
        );
    }

    public static function find_by_store($storeID) {
        $storeID = (int) $storeID;
        foreach (self::$stores as $store) {
            if ($store->id == $storeID) return $store;
        }
        return FALSE;
    }

    public static function get_total_products() {
        $total = 0;
        foreach (self::$stores as $store)
            $total += $store->get_total_products();
        return $total;
    }

    public static function get_total_products_by_city($city) {
        $stores = self::find_by_city((int) $city);
        $total = 0;
        foreach ($stores as $store)
            $total += $store->get_total_products();
        return $total;
    }

    public static function get_product_total_by_city($productName,$city) {
        return self::product_total($productName,self::find_by_city((int) $city));
    }

    public static function get_product_total_by_store($productName,$storeID) {
        $res = self::find_by_store((int) $storeID);
        return $res ? self::product_total($productName,array($res)) : $res;
    }

    public static function get_product_total($productName) {
        return self::product_total($productName,self::$stores);
    }

    private static function product_total($productName,$stores=NULL) {
        $total = 0;
        foreach ($stores as $store)
            $total += $store->get_product_total($productName);
        return $total;
    }

}

class Store {

    public $id;
    public $city;
    public $products;

    function __construct($id,$city,$products=array()) {
        $this->id = $id;
        $this->city = $city;
        $this->products = $products;
    }

    public function get_total_products() {
        return array_sum($this->products);
    }

    public function get_product_total($productName) {
        if (isset($this->products[$productName]))
            return (int) $this->products[$productName];
        return 0;
    }

}

will output

total products: 242
total products in city #309: 242
"apples" everywhere: 72
"apples" in store #12: 21
"apples" in city #309: 72

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.