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 =>
开发者_Python百科 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 ?
$res = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
if ($k === 'object_id') {
$res[] = $v;
}
}
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
)
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
Based on @goat answer, I wrote a little function which :
- find values by keys in multidimensional arrays (regardless of the level)
- exclude empty values
- remove duplicates if needed
- returns
false
if empty
function :
function array_find_recursive($arr, $key, $unique = false) {
$res = false;
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
if ($k === $key && $v != "") {
$res[] = $v;
}
}
if($unique)
return array_unique($res);
return $res;
}
Use regardless of duplicates :
$result = array_find_recursive($my_array, 'key');
Use excluding duplicates :
$result = array_find_recursive($my_array, 'my_key', true);
精彩评论