Могу ли я получить все ключи многоуровневых ассоциативных массивов в php - PullRequest
0 голосов
/ 02 февраля 2010

Есть ли способ в php, где я могу получить n ключей уровня для многомерного массива в php?

Вот мой ассоциативный массив, и в качестве вывода я хочу массив, который будет содержать все значения для ключей object_id, как вы можете там из самой структуры, есть много вложенных уровней для object_id, и как мне получить значения для ключей 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

Выходные данные должны быть массивом, который будет содержать все значения для ключей = object_id. Пожалуйста, посоветуйте?

Ответы [ 4 ]

6 голосов
/ 03 февраля 2010
$res = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
    if ($k === 'object_id') {
        $res[] = $v;
    }
}
5 голосов
/ 03 февраля 2010

Решение Dereleased будет быстрее, я думаю (так как оно использует внутренние циклы), моё также может работать со значениями массива для ключей object_id. Ваш компромисс;)


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;
}

Как видите, массив результатов присваивается каждому вызову функции в качестве ссылки (обозначается &). Таким образом, каждый рекурсивный вызов этой функции имеет доступ к тому же массиву и может просто добавить поиск.

Вы можете сделать:

$values = find_all('object_id', $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
)
2 голосов
/ 03 февраля 2010

Мое тестирование должно было быть простым, потому что я не собираюсь тратить время на перевод любого предоставленного вами дампа в рабочий массив; если это не работает, предоставьте var_export массива для тестирования.

Это, однако, звучит как работа для 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));

Последний параметр array_walk_recursive является ссылкой в ​​массиве, потому что, поскольку передача по времени вызова устарела, это единственный способ (, отличный от некоторой замысловатой структуры объекта См. Ниже ), чтобы передать ссылку на контейнер в функцию обработчика.

Этот код должен заполнить $coll всеми значениями, в качестве ключа которых указан 'object_id'. Это не будет работать в случаях, когда 'object_id' является массивом, потому что это известное поведение array_walk_recursive() (то есть функция обратного вызова не инициируется для элементов, которые сами являются массивами).

РЕДАКТИРОВАТЬ (для великого правосудия):

Структура объекта на самом деле не такая запутанная, поэтому, если вы хотите избежать посторонних массивов / ссылочных конструкций, вот как это сделать:

$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);

Как это работает

Функция PHP array_walk_recursive() принимает заданный массив в качестве первого параметра и выполняет итерацию по каждой паре ключ / значение. Если значение является скалярным, оно передает комбинацию ключ / значение некоторой пользовательской функции обратного вызова; однако, если значение является массивом, array_walk_recursive() будет рекурсивно вызывать себя и продолжать вести себя таким же образом. Он будет работать таким образом до тех пор, пока не пройдет через все элементы массива.

Второй параметр - это функция обратного вызова для использования; в этом случае я написал и объявил функцию (array_get_keys) и передал ее имя в виде строки во втором параметре. Таким образом, функция зарегистрирована array_walk_recursive() и является функцией, выполняемой каждый раз, когда обрабатывается пара ключ / значение.

Третий параметр в обоих примерах - это, по сути, часть «дополнительных» данных, которые мы можем передать нашей функции обратного вызова, чтобы изменить ее поведение - в этом случае это массив (или во втором примере контейнер ArrayObject) который (а) определен в глобальной области и (б) используется для хранения всех значений, для которых $key == 'object_id' имеет значение true.

В первом примере я использую синтаксис array(&$coll) для передачи переменной коллекции, потому что это единственный способ передать ссылку на коллекцию, чтобы ее можно было изменить в глобальной области видимости (в противном случае у нас нет способ получения списка). Во втором примере я объявляю $coll как ArrayObject, что делает его неявно передаваемым по ссылке, поэтому нет необходимости содержать его в массиве, чтобы гарантировать его изменение в глобальной области.

1 голос
/ 03 февраля 2010

Альтернатива проверке цикла object_id в foreach при использовании итераторов Spl:

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));
    }
}

Подклассы, расширяющие FilterIterator, должны реализовывать метод accept(). Внутри, при переборе массива с foreach, итератор фильтра вызовет ваш метод accept и пропустит все элементы, для которых тест, записанный в методе, вернет false FilterIterators можно наращивать, поэтому вы можете объединить несколько FilterIterator в цепочку фильтров, что делает этот подход очень гибким.

Вы бы использовали это так

$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;
}

Подробнее о SplIterators:

...