【问题标题】:Can I get all keys of an multi level associative arrays in php我可以在php中获取多级关联数组的所有键吗
【发布时间】:2010-02-02 20:54:50
【问题描述】:

php 中有什么方法可以让我在 php 中获取多维数组的 n 级键吗?

这是我的关联数组,作为输出,我想要一个包含所有键值的数组键 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 的所有值。请指教?

【问题讨论】:

  • 您能否提供一份由var_export 生成的数组副本用于测试目的?
  • 我担心这会发生冲突。您正在提取键而不是值,并且您的键不是唯一的,尤其是在多个级别上。下面的递归函数是要走的路,但每个非唯一键都会覆盖最后一个。如果这是您想要的,那就太好了,请记住这一点。
  • @Shane:你什么意思?这些值被添加到结果数组中。它们不必是唯一的,也不会覆盖值。
  • @Shane :我不想覆盖以前的键,所以有什么办法可以避免这种情况。

标签: php arrays associative-array


【解决方案1】:
$res = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($arr), RecursiveIteratorIterator::SELF_FIRST) as $k => $v) {
    if ($k === 'object_id') {
        $res[] = $v;
    }
}

【讨论】:

    【解决方案2】:

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

    如您所见,函数的每次调用都会将结果数组作为引用(用& 表示)。这样,这个函数的每个递归调用都可以访问 same 数组,并且可以添加一个 find。

    你可以这样做:

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

    【讨论】:

    • 您也可以在函数声明中键入提示 $resultarray,因为将其初始化为 null 不仅有效,而且会以可接受的方式处理不存在的情况.只是说'=)
    • 你能解释一下这段代码的工作原理吗,因为我无法理解如何处理这段代码。如果您能分享一些关于它的见解,将不胜感激
    • @Rachel:我添加了一些 cmets。
    • @Felis:感谢 cmets,有什么方法可以获取重复值,因为现在重复值正在被删除。
    • @Rachel:不,它们没有被删除。在我的示例数组条目41520 中是相同的。值只是被添加,如果一个值已经存在,新的值仍然会被添加。
    【解决方案3】:

    我的测试必须简单,因为我不会花时间将您提供的任何转储转换为工作数组;如果这不起作用,请提供数组的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 的最后一个参数是数组中的引用,因为调用时传递引用已被弃用,这是唯一的方法(除了一些复杂的对象结构 见下文)将对容器的引用传递给处理函数。

    此代码应使用以“object_id”作为键的所有值填充$coll。它不适用于 '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 容器) (a) 在全局范围内定义,(b) 用于存储所有 $key == 'object_id' 为真的值。

    在第一个示例中,我使用语法array(&$coll) 来传递集合变量,因为这是传递对集合的引用以便可以在全局范围内修改它的唯一方法(否则,我们没有检索列表的方法)。在第二个示例中,我将$coll 声明为ArrayObject,这使其通过引用隐式传递,因此无需将其包含在数组中以确保在全局范围内对其进行修改。

    【讨论】:

    • 这会给我 key = object_id 的所有值吗?您能否解释一下这段代码的工作原理,因为我无法理解它?
    • 是的,它会为您提供 key == 'object_id' 的所有值,并将它们插入到数组中,我将添加更多解释。
    • 感谢 Dereleased 的恰当解释。这真的很有帮助。
    【解决方案4】:

    使用 Spl 迭代器时在 foreach 循环中检查 object_id 的替代方法:

    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 的任何元素。 FilterIterator 是可堆叠的,因此您可以将多个 FilterIterator 组合到一个 Filter Chain 中,这是一种非常灵活的方法。

    你会这样使用它

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

    更多关于拆分器的信息:

    【讨论】:

      【解决方案5】:

      根据@goat 的回答,我写了一个小函数:

      • 在多维数组中按键查找值(无论级别如何)
      • 排除空值
      • 根据需要删除重复项
      • 如果为空则返回false

      功能:

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

      不考虑重复使用:

      $result = array_find_recursive($my_array, 'key');
      

      使用排除重复项:

      $result = array_find_recursive($my_array, 'my_key', true);
      

      【讨论】:

        猜你喜欢
        • 2013-02-17
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        • 2019-06-21
        • 2016-11-05
        • 1970-01-01
        • 2012-06-29
        • 1970-01-01
        相关资源
        最近更新 更多