tags:

views:

267

answers:

4

I have an array called $all_countries following this structure:

Array
(
    [0] => Array
        (
            [countries] => Array
                (
                    [id] => 1
                    [countryName] => Afghanistan
                )

        )

    [1] => Array
        (
            [countries] => Array
                (
                    [id] => 2
                    [countryName] => Andorra
                )

        )
)

I want to loop through an array called prohibited_countries and unset the entire [countries] element that has a countryName matching.

foreach($prohibited_countries as $country){
  //search the $all_countries array for the prohibited country and remove it...

}

Basically I've tried using an array_search() but I can't get my head around it, and I'm pretty sure I could simplify this array beforehand using Set::extract or something?

I'd be really grateful if someone could suggest the best way of doing this, thanks.

+1  A: 

Well first of all id e teh array in the format:

  Array(
    'Andorra' => 2,
    'Afghanistan' => 1
  );

Or if you need to have the named keys then i would do:

  Array(
    'Andorra' => array('countryName'=> 'Andorra', 'id'=>2),
    'Afghanistan' => array('countryName'=> 'Afghanistan', 'id'=>1)
  );

then i would jsut use an array_diff_keys:

  // assuming the restricted and full list are in the same 
  // array format as outlined above:
  $allowedCountries = array_diff_keys($allCountries, $restrictedCountries);

If your restricted countries are just an array of names or ids then you can use array_flip, array_keys, and/or array_fill as necessary to get the values to be the keys for the array_diff_keys operation.

You could also use array_map to do it.

prodigitalson
+1  A: 

Try something like this (it's probably not the most efficient way, but it should work):

for ($i = count($all_countries) - 1; $i >= 0; $i--) {
    if (in_array($all_countries[$i]['countries']['countryName'], $prohibited_countries) {
        unset($all_countries[$i]);
    }
}
RaYell
+1  A: 

If you wanted to use the Set class included in CakePHP, you could definitely reduce the simplicity of your country array with Set::combine( array(), key, value ). This will reduce the dimensionality (however, you could do this differently as well. It looks like your country array is being created by a Cake model; you could use Model::find( 'list' ) if you don't want the multiple-dimension resultant array... but YMMV).

Anyway, to solve your core problem you should use PHP's built-in array_filter(...) function. Manual page: http://us3.php.net/manual/en/function.array-filter.php

Iterates over each value in the input array passing them to the callback function. If the callback function returns true, the current value from input is returned into the result array. Array keys are preserved.

Basically, pass it your country array. Define a callback function that will return true if the argument passed to the callback is not on the list of banned countries.

Note: array_filter will iterate over your array, and is going to be much faster (execution time-wise) than using a for loop, as array_filter is a wrapper to an underlying C function. Most of the time in PHP, you can find a built-in to massage arrays for what you need; and it's usually a good idea to use them, just because of the speed boost.

HTH, Travis

Travis Leleu
+2  A: 

Here's an example using array_filter:

$all_countries = ...
$prohibited_countries = array('USA', 'England'); // As an example
$new_countries = array_filter($all_countries, create_function('$record', 'global $prohibited_countries; return !in_array($record["countries"]["countryName"], $prohibited_countries);'));

$new_countries now contains the filtered array

mscdex