【问题标题】:Loop over multidimensional array and use parent key as prefix循环遍历多维数组并使用父键作为前缀
【发布时间】:2016-01-23 23:25:49
【问题描述】:

在 Laravel 4 或 5 中使用 Eloquent 时,$model->with() 方法使用该方法作为关系名称。因此,如果我们得到一个用户的个人资料,那将返回:

$user = [
  'id' => 1,
  'name' => 'Example',
  'profile' => [
    'last_login' => '10-10-1900',
    'another_field' => 'with some data',
    'actions' => [
      0 => 'Logged in',
      1 => 'Logged out',
      2 => 'Signed up for news letter'
    ]
  ]
];

我想展平整个数组并使用关系的键作为前缀,所以即:

$user = [
  'id' => 1,
  'name' => 'Example',
  'profile_last_login' => '10-10-1900',
  'profile_another_field' => 'with some data',
  'profile_actions' => [
    0 => 'Logged in',
    1 => 'Logged out',
    2 => 'Signed up for news letter'
  ]
];

我怎样才能做到这一点?

编辑

我也想展平多维数组,像这样:

$user = [
    'id' => 1,
    'name' => 'Example',
    'profile' => [
        'last_login' => '10-10-1900',
        'another_field' => 'with some data',
        'actions' => [
            0 => 'Logged in',
            1 => 'Logged out',
            2 => 'Signed up for news letter'
        ],
        'friends' => [
            'friend_one' => [
                'name' => 'Test User',
                'email' => 'test@example.com'
            ],
            'friend_two' => [
                'name' => 'Test User',
                'email' => 'test@example.com'
            ]
        ]
    ]
];

进入这个:

$out = [
    'id' => 1,
    'name' => 'Example',
    'profile_last_login' => '10-10-1900',
    'profile_another_field' => 'with some data',
    'profile_actions' => [
        0 => 'Logged in',
        1 => 'Logged out',
        2 => 'Signed up for news letter'
    ],
    'profile_friends_friend_one_name' => 'Test User',
    'profile_friends_friend_one_email' => 'test@example.com',
    'profile_friends_friend_two_name' => 'Test User',
    'profile_friends_friend_two_email' => 'test@example.com'
];

【问题讨论】:

    标签: php arrays multidimensional-array laravel-5


    【解决方案1】:

    原始问题的简单方法(单维)

    function flattenParentKey($array, $parentKey)
    {
        foreach ($array[$parentKey] as $key => $value)
        {
            $array[$parentKey . '_' . $key] = $value;
        }
    
        unset($array[$parentKey]);
    
        return $array;
    }
    

    这是 PHP Shell (php -a) 中的一个示例:

    php > $user = [
    php >   'id' => 1,
    php >   'name' => 'Example',
    php >   'profile' => [
    php >     'last_login' => '10-10-1900',
    php >     'another_field' => 'with some data',
    php >     'actions' => [
    php >       0 => 'Logged in',
    php >       1 => 'Logged out',
    php >       2 => 'Signed up for news letter'
    php >     ]
    php >   ]
    php > ];
    php > $user = flattenParentArray($user, 'profile');
    php > var_dump($user);
    array(5) {
      ["id"]=>
      int(1)
      ["name"]=>
      string(7) "Example"
      ["profile_last_login"]=>
      string(10) "10-10-1900"
      ["profile_another_field"]=>
      string(14) "with some data"
      ["profile_actions"]=>
      array(3) {
        [0]=>
        string(9) "Logged in"
        [1]=>
        string(10) "Logged out"
        [2]=>
        string(25) "Signed up for news letter"
      }
    }
    php >
    

    多维数组的递归方法

    正如您在 cmets 中所问的那样,我在您原来的问题中添加了以下内容,这是我们如何使用嵌套的多维数组来做到这一点的:

    $user = [
        'id' => 1,
        'name' => 'Example',
        'profile' => [
            'last_login' => '10-10-1900',
            'another_field' => 'with some data',
            'actions' => [
                0 => 'Logged in',
                1 => 'Logged out',
                2 => 'Signed up for news letter'
            ],
            'friends' => [
                'friend_one' => [
                    'name' => 'Test User',
                    'email' => 'test@example.com'
                ],
                'friend_two' => [
                    'name' => 'Test User',
                    'email' => 'test@example.com'
                ]
            ]
        ]
    ];
    
    /* Returns true if the specified parameter is an array, is not empty, and is 
     * not a contiguous numeric array).
     */
    function isAssociativeArray($array)
    {
        if (empty($array) || !is_array($array))
        {
            return false;
        }
    
        /* Returns true if arrays keys are not numeric or contiguous. */
        return (bool) array_keys($array) !== range(0, count($array) - 1);
    }
    
    /* $parentKey will always be null when we first call this function. As
     * it recurses through levels of depth, $parentKey will be passed and
     * appended to.
     */
    function flattenChildArrays($array, $parentKey = null)
    {
        $outputArray = [];
    
        foreach ($array as $key => $value)
        {
            /* If we have a $parentKey, our new key will be "$parentKey_$key" */
            $newKey = (($parentKey) ? $parentKey . '_' . $key : $key);
    
            if (isAssociativeArray($value))
            {
                /* If our $value is an associative array, we'll want to recursively
                 * call ourselves again on $value with our new key as the $parentKey.
                 */
                $outputArray = array_merge($outputArray, flattenChildArrays($value, $newKey));
            }
            else
            {
                /* If $value is not an associative array (i.e. just a simple value, or a
                 * contiguous numeric array, just use the value as it is in our output
                 * array. If we have a parent key (because we're inside 1 or more levels
                 * of recursion), use "$parentKey_$key" (see where we define $newKey above).
                 */
                $outputArray[$newKey] = $value;
            }
        }
    
        return $outputArray;
    }
    

    还有一个 PHP shell 中的示例:

    php > $user = [
    php >     'id' => 1,
    php >     'name' => 'Example',
    php >     'profile' => [
    php >         'last_login' => '10-10-1900',
    php >         'another_field' => 'with some data',
    php >         'actions' => [
    php >             0 => 'Logged in',
    php >             1 => 'Logged out',
    php >             2 => 'Signed up for news letter'
    php >         ],
    php >         'friends' => [
    php >             'friend_one' => [
    php >                 'name' => 'Test User',
    php >                 'email' => 'test@example.com'
    php >             ],
    php >             'friend_two' => [
    php >                 'name' => 'Test User',
    php >                 'email' => 'test@example.com'
    php >             ]
    php >         ]
    php >     ]
    php > ];
    php > var_dump(flattenChildArrays($user));
    array(11) {
      ["id"]=>
      int(1)
      ["name"]=>
      string(7) "Example"
      ["profile_last_login"]=>
      string(10) "10-10-1900"
      ["profile_another_field"]=>
      string(14) "with some data"
      ["profile_actions_0"]=>
      string(9) "Logged in"
      ["profile_actions_1"]=>
      string(10) "Logged out"
      ["profile_actions_2"]=>
      string(25) "Signed up for news letter"
      ["profile_friends_friend_one_name"]=>
      string(9) "Test User"
      ["profile_friends_friend_one_email"]=>
      string(16) "test@example.com"
      ["profile_friends_friend_two_name"]=>
      string(9) "Test User"
      ["profile_friends_friend_two_email"]=>
      string(16) "test@example.com"
    }
    php >
    

    递归可能是一个难以理解的话题,因为它需要您在脑海中通过多个层次来跟踪程序,并且很容易忘记自己的位置。我建议举一个简单的例子,逐行“逐步执行”你的递归函数,注释每个值在每个深度级别上的含义。

    this question 的答案提供了有关理解递归的更多信息。

    【讨论】:

    • 可以在10级以上的数组上使用这个吗?
    • 我没有示例,但是数组发生了变化,因为我在雄辩的数据上使用它来将其全部展平
    • 我明白了。您可以多次调用它,也可以在 recursive 函数中调用它。
    • 我假设,在你原来的例子中,你不想扁平化[profile_actions],对吧?
    • 当然,我可以帮忙。我得跑个急事,但给我一个小时左右:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    相关资源
    最近更新 更多