问题描述:

Is there any way in php wherein I can get n level keys for multi-dimensional array in php ?

Here is my associative array and as output I want an array which would contain all the values for keys object_id as you can there from the structure itself there are many nested levels for object_id and so how can I get all the values for keys object_id ?

 array

'cart' =>

array

12061 =>

array

'object_id' => string '12061' (length=5)

'discriminator' => string 'SimpleProductOffering' (length=21)

'spec' =>

array

100012061 =>

array

'object_id' => string '100012061' (length=9)

'discriminator' => string 'CompositeProductSpecification' (length=29)

'trait' =>

array

'MAIN_CPE' =>

array

'object_id' => string '1000000000015' (length=13)

'is_configurable' => string '0' (length=1)

'trait_value' =>

array

10001 =>

array

'object_id' => string '10001' (length=5)

'collateral' =>

array

empty

'collateral' =>

array

empty

'offer_type' => null

'price' =>

array

12862 =>

array

'object_id' => string '12862' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12876 =>

array

'object_id' => string '12876' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

0 => string '12876' (length=5)

1 => string '12894' (length=5)

'collateral' =>

array

empty

'contained_offers' =>

array

empty

'family' =>

array

0 => string 'TV Subscription' (length=24)

'relationship' =>

array

'CHILDREN' =>

array

'object_id' => string '1206102000' (length=10)

'min' => string '0' (length=1)

'max' => string '1000000' (length=7)

'related_offer' =>

array

0 => string '10410' (length=5)

1 => string '10411' (length=5)

'REQUIREMENTS' =>

array

'object_id' => string '1206104000' (length=10)

'min' => string '1' (length=1)

'max' => string '1' (length=1)

'related_offer' =>

array

0 => string '11950' (length=5)

1 => string '11990' (length=5)

'EXCLUSIONS' =>

array

'object_id' => string '1206101000' (length=10)

'min' => string '1' (length=1)

'max' => string '1' (length=1)

'related_offer' =>

array

0 => string '12062' (length=5)

1 => string '12063' (length=5)

'ALTERNATIVES' =>

array

'object_id' => string '1206105000' (length=10)

'min' => string '1' (length=1)

'max' => string '1' (length=1)

'related_offer' =>

array

0 => string '12263' (length=5)

'BUNDLE_ITEMS' =>

array

'object_id' => string '1206106000' (length=10)

'min' => string '1' (length=1)

'max' => string '1' (length=1)

'related_offer' =>

array

0 => string '12062' (length=5)

'financial_terms' =>

array

'billing_period' =>

array

0 => string 'QUARTERLY' (length=9)

'payment_method' =>

array

0 => string 'DIRECT_DEBIT' (length=12)

'bill_presentation' =>

array

0 => string 'PAPER' (length=5)

'contract_constraints' =>

array

'min_contract_period' => int 24

'cancellation_period' => string 'ALWAYS' (length=6)

'notice_period' => int 3

'rollover_period' => int 2

'right_of_wd_period' => int 1

'collateral' =>

array

empty

10017 =>

array

'object_id' => string '10017' (length=5)

'spec' =>

array

100010017 =>

array

'object_id' => string '100010017' (length=9)

'discriminator' => string 'CompositeProductSpecification' (length=29)

'trait' =>

array

empty

'offer_type' => null

'price' =>

array

300306 =>

array

'object_id' => string '300306' (length=6)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12894 =>

array

'object_id' => string '12894' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12862 =>

array

'object_id' => string '12862' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12876 =>

array

'object_id' => string '12876' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

0 => string '12876' (length=5)

1 => string '12894' (length=5)

'collateral' =>

array

empty

'contained_offers' =>

array

0 => null

'family' =>

array

empty

'relationship' =>

array

'EXCLUSIONS' =>

array

'object_id' => string '1001701000' (length=10)

'min' => string '1' (length=1)

'max' => string '1' (length=1)

'related_offer' =>

array

0 => string '11893' (length=5)

14 => string '12305' (length=5)

15 => string '12306' (length=5)

'financial_terms' =>

array

'billing_period' =>

array

0 => string 'MONTHLY' (length=7)

1 => string 'QUARTERLY' (length=9)

'payment_method' =>

array

0 => string 'DIRECT_DEBIT' (length=12)

1 => string 'DIRECT_DEBIT' (length=12)

'bill_presentation' =>

array

0 => string 'EMAIL' (length=5)

1 => string 'PAPER' (length=5)

'contract_constraints' =>

array

'min_contract_period' => int 24

'cancellation_period' => string 'ALWAYS' (length=6)

'notice_period' => int 3

'rollover_period' => int 2

'right_of_wd_period' => int 1

'collateral' =>

array

empty

0 =>

array

11990 =>

array

'object_id' => string '11990' (length=5)

'discriminator' => string 'SimpleProductOffering' (length=21)

'spec' =>

array

100011990 =>

array

'object_id' => string '100011990' (length=9)

'discriminator' => string 'CompositeProductSpecification' (length=29)

'trait' =>

array

empty

'offer_type' => null

'price' =>

array

12862 =>

array

'object_id' => string '12862' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12876 =>

array

'object_id' => string '12876' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

10017 =>

array

'object_id' => string '10017' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

12894 =>

array

'object_id' => string '12894' (length=5)

'discriminator' => string 'RecurringChargeProdOfferPriceCharge' (length=35)

'price_alteration' =>

array

empty

'collateral' =>

array

empty

'collateral' =>

array

empty

'contained_offers' =>

array

empty

'family' =>

array

0 => string 'CATV' (length=4)

'relationship' =>

array

empty

'financial_terms' =>

array

'billing_period' =>

array

0 => string 'QUARTERLY' (length=9)

'payment_method' =>

array

0 => string 'DIRECT_DEBIT' (length=12)

'bill_presentation' =>

array

0 => string 'PAPER' (length=5)

'contract_constraints' =>

array

'min_contract_period' => int 24

'collateral' =>

array

empty

Output should be an array which would contain all the values for keys = object_id. Kindly advise ?

网友答案:

Dereleased's solution will be faster I guess (as it uses internal loops), mine can also deal with array values for object_id keys. Your tradeoff ;)


function find_all($needle, array $haystack, array &$result = null) {
    // This is to initialize the result array and is only needed for
    // the first call of this function
    if(is_null($result)) {
        $result = array();
    }
    foreach($haystack as $key => $value) {
        // Check whether the key is the value we are looking for. If the value
        // is not an array, add it to the result array.
        if($key === $needle && !is_array($value)) {
            $result[] = $value;
        }
        if(is_array($value)) {
            // If the current value is an array, we perform the same
            // operation with this 'subarray'.
            find_all($needle, $value, $result);
        }
    }
    // This is only needed in the first function call to retrieve the results
    return $result;
}

As you can see, the result array is given to every call of the function as reference (denoted by the &). This way, every recursive call of this function has access to the same array and can just add a find.

You can do:

$values = find_all('object_id', $array);

It gives me for your array:

Array
(
    [0] => 12061
    [1] => 100012061
    [2] => 1000000000015
    [3] => 10001
    [4] => 12862
    [5] => 12876
    [6] => 1206102000
    [7] => 1206104000
    [8] => 1206101000
    [9] => 1206105000
    [10] => 1206106000
    [11] => 10017
    [12] => 100010017
    [13] => 300306
    [14] => 12894
    [15] => 12862
    [16] => 12876
    [17] => 1001701000
    [18] => 11990
    [19] => 100011990
    [20] => 12862
    [21] => 12876
    [22] => 10017
    [23] => 12894
)
网友答案:
$res = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
    if ($k === 'object_id') {
        $res[] = $v;
    }
}
网友答案:

My testing had to be simple because I am not going to take the time to translate whatever dump you have provided into a working array; if this doesn't work, please provide a var_export of the array for testing purposes.

This, however, sounds like a job for array_walk_recursive().

$coll = array();

function array_get_keys($value, $key, $c) {
    if (strcasecmp($key,'object_id')==0) {
        array_push($c[0],$value);
    }
}

array_walk_recursive($array, 'array_get_keys', array(&$coll));

The last parameter to array_walk_recursive is a reference in an array because, since call-time pass-by-reference has been deprecated, that is the only way (other than some convoluted object structure See Below) to pass a reference to the container to the handler function.

This code should populate $coll with all the values that have 'object_id' as their key. It will not work for cases where 'object_id' is an array, because this is known behavior of array_walk_recursive() (that is, the callback function is not initiated for elements which are themselves arrays).

EDIT (for great justice):

The object structure is not actually that convoluted, so if you wish to avoid extraneous array/reference constructs, here's how to do it:

$coll = new ArrayObject;

function array_get_keys($value, $key, $c) {
    if (strcasecmp($key,'object_id')==0) {
        $c[] = $value;
    }
}

array_walk_recursive($array, 'array_get_keys', $coll);

How it works

PHP's array_walk_recursive() function takes a given array for its first parameter and iterates over each key/value pair. If the value is scalar, it passes the key/value combination to some user-defined callback function; however, if the value is an array, then array_walk_recursive() will recursively call itself, and continue to behave in the same manner. It will work in this way until it has looped through every element in the array.

The second parameter is the callback function to use; in this case, I have written and declared a function (array_get_keys) and passed its name as a string in the second parameter. Thus, the function is registered by array_walk_recursive() and is the function executed each time a key/value pair is processed.

The third parameter in both examples is basically a piece of "extra" data we can pass to our callback function to alter its behavior -- in this case, it is an array (or in the second example, an ArrayObject container) which is (a) defined in the global scope and (b) used to store all the values for which $key == 'object_id' is true.

In the first example, I use the syntax array(&$coll) to pass the collection variable, because that is the only way to pass a reference to the collection so that it can be modified in the global scope (otherwise, we have no way to retrieve the list). In the second example, I declare $coll as an ArrayObject, which makes it implicitly passed by reference, so there is no need to contain it in an array to ensure it is modified in the global scope.

网友答案:

Alternative to checking for object_id in foreach loop when using Spl Iterators:

class KeyFilter extends FilterIterator
{
    protected $acceptedKeys; // keys to return when iterating over the array

    public function __construct(array $keys, $iterator)
    {
        $this->acceptedKeys = $keys;
        parent::__construct($iterator);
    }

    public function accept()
    {
        // skip elements that return false when iterating
        return (in_array($this->key(), $this->acceptedKeys));
    }
}

Subclasses extending FilterIterator must implement the accept() method. Internally, when iterating over your array with foreach, the filter iterator will call your accept method and skip any elements for which the test written in the method will return false. FilterIterators are stackable, so you can combine multiple FilterIterators to a Filter Chain, which makes this a very flexible approach.

You'd use it like this

$yourArray = new KeyFilter(array('object_id' /* add more */),
                           new RecursiveIteratorIterator(
                               new RecursiveArrayIterator($yourArray)));

foreach($yourArray as $key => $value) {
    // will only return elements with an object_id key
    echo $key, '--', $value, PHP_EOL;
}

More on SplIterators:

  • http://www.phpro.org/tutorials/Introduction-to-SPL.html
相关阅读:
Top