Page 1 of 1

Array Key Shuffling

Posted: Fri Apr 03, 2009 9:41 pm
by McInfo
I need a function that will turn this array:
$old_array
[text]Array
(
[images] => Array
(
[name] => Array
(
[0] => sheet-v2.png
[1] => 05logo.png
)
[type] => Array
(
[0] => image/png
[1] => image/png
)
[tmp_name] => Array
(
[0] => C:\xampp\tmp\php474F.tmp
[1] => C:\xampp\tmp\php4750.tmp
)
[error] => Array
(
[0] => 0
[1] => 0
)
[size] => Array
(
[0] => 81537
[1] => 1143
)
)
)[/text]
into this array:
$new_array
[text]Array
(
[images] => Array
(
[0] => Array
(
[name] => sheet-v2.png
[type] => image/png
[tmp_name] => C:\xampp\tmp\php474F.tmp
[error] => 0
[size] => 81537
)
[1] => Array
(
[name] => 05logo.png
[type] => image/png
[tmp_name] => C:\xampp\tmp\php4750.tmp
[error] => 0
[size] => 1143
)
)
)[/text]
I don't want a custom function that works only with this array. (I already wrote one.) I want a generalized function that works with an unknown number of sub-arrays. Some limitations are that the innermost arrays all have to have the same keys and be at the same depth.

The function call might look something like this:

Code: Select all

<?php
$new_array = array_key_shuffle($old_array, array(0, 2, 1));
?>
The second argument is an array that tells the function how to order the hierarchy.

Has anyone tackled this challenge before? The recursion is turning my brain to mush.

I think I am half-way to a solution, though. I made a function that flattens the array keys:

Code: Select all

<?php
/**
 * Lists array keys recursively, stops at the first non-array
 *
 * @param array $a - the input array
 * @param integer $i - (for recursive calls only)
 * @param array $k - (for recursive calls only)
 * @return array
 */
function array_keys_r ($a, $i = 0, $k = array())
{
    if (is_array($a))
    {
        $k[$i] = array_keys($a);
        return array_keys_r($a[$k[$i][0]], $i + 1, $k);
    }
    else
        return $k;
}
?>
It turns $old_array into this:
$old_array_keys
[text]Array
(
[0] => Array
(
[0] => images
)
[1] => Array
(
[0] => name
[1] => type
[2] => tmp_name
[3] => error
[4] => size
)
[2] => Array
(
[0] => 0
[1] => 1
)
)[/text]
Sorry for the long post. (I thought I would make it just a little bit longer by putting this sentence in here.)

Edit: This post was recovered from search engine cache.

Re: Array Key Shuffling

Posted: Fri Apr 03, 2009 9:48 pm
by Benjamin
Well, as I said in the post I am about to refer you to, this smells funny. This is not exactly what you are after but may help you with the recursion issues you are facing.

viewtopic.php?p=524664

Re: Array Key Shuffling

Posted: Fri Apr 03, 2009 11:51 pm
by requinix

Code: Select all

<?php
 
$test = array(
    "images" => array(
            "name" => array(
                    0 => "sheet-v2.png",
                    1 => "05logo.png"
                ),
            "type" => array(
                    0 => "image/png",
                    1 => "image/png"
                ),
            "tmp_name" => array(
                    0 => "C:\\xampp\\tmp\\php474F.tmp",
                    1 => "C:\\xampp\\tmp\\php4750.tmp"
                ),
            "error" => array(
                    0 => 0,
                    1 => 0
                ),
            "size" => array(
                    0 => 81537,
                    1 => 1143
                )
        )
);
 
// preconditions--
// $array:
// - all keys on the same level must be different
// - except the innermost arrays must all have the same keys
// - same depth everywhere
// $shuffle:
// - must be a shuffling of {0,1,2,3...N-1} where N<=$array depth
function array_key_reorder($array, $shuffle) {
    // rearrange into something that we can use
    $shuffle = array_flip(array_values($shuffle)); ksort($shuffle);
    // we need the last key separate from the rest
    $shufflelast = array_pop($shuffle);
    // final array and maximum depth
    $result = array(); $depth = count($shuffle) + 1;
    // complicated
    // keylist[X][0] is an array of keys that provide a "path" to traverse to reach
    // keylist[X][1], the value located after traversing the key path
    $keylist = array(); foreach ($array as $k => $v) $keylist[] = array(array($k), $v);
    
    // this loop is complicated. we could solve the recursive problem with recursion,
    // but that would involve another function. this way we collapse the problem
    // into an ever-expanding list of stuff
    // this same strategy can be used to print a recursive directory listing without
    // ever using recursion
    //
    // it keeps a list of key paths and, when the path is long enough, it does
    // something special. until it gets there, it looks at the current key path
    // and enters its one child into the list. eventually the loop will reach that
    // child's key list, then stores its children, and keeps going
    //
    // for example, when used with a directory listing, the key list might end up
    // as (newlines added to show how it works):
    //  C:\, (level 0)
    //  C:\Users, C:\Windows, (level 1)
    //  C:\Users\Me, C:\Windows\Fonts, C:\Windows\System32, (level 2)
    //  C:\Users\Me\Documents (level 3)
    while (list(, $k) = each($keylist)) {
        // go down through the tree
        if (count($k[0]) < $depth) {
            // use the current path + current key as a new entry in $keylist
            foreach ($k[1] as $k2 => $v2) $keylist[] = array(array_merge($k[0], array($k2)), $v2);
        // if we hit the "end" of the tree
        } else if (count($k[0]) == $depth) {
            // go through the shuffled key list to store the value into the
            // $result array according to the new key path
            $r =& $result;
            // until the last key, create new arrays in $result as needed
            foreach ($shuffle as $n => $k2) {
                $k3 = $k[0][$k2];
                if (!isset($r[$k3])) $r[$k3] = array(); $r =& $r[$k3];
            }
            // the last key is used to assign the new value, not create a blank array
            $r[$k[0][$shufflelast]] = $k[1];
        }
    }
    return $result;
}
 
header("Content-Type: text/plain");
print_r(array_key_reorder($test, array(0, 2, 1)));

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 12:00 am
by John Cartwright
Nice to see non-recursive solutiosn :)

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 12:32 am
by McInfo
Thanks for the ideas. I'll take a closer look at them after I get some sleep.

Edit: This post was recovered from search engine cache.

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 2:45 am
by Benjamin
John Cartwright wrote:Nice to see non-recursive solutiosn :)
What is wrong with recursion? How is recursion different than a while loop executing on the value of a variable?

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 2:52 am
by requinix
astions wrote:How is recursion different than a while loop executing on the value of a variable?
It's... completely different. What are you getting at?

I think he's getting at the "99% of people would immediately try to do a recursive solution so it's nice to see somebody in the 1% who tries to do it differently." Then again, that somebody is me so maybe I'm a bit biased...

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 3:15 am
by John Cartwright
It is not so much of a problem with PHP, as PHP does a pretty good at limiting the amount of recursion allowed. Although, it mostly comes down to limiting memory consumption and avoiding potential stack overflows.

Re: Array Key Shuffling

Posted: Sat Apr 04, 2009 3:32 am
by Benjamin
tasairis wrote:It's... completely different. What are you getting at?
Ah it's nothing against you or your solution don't worry. The issue is that recursion is commonly used in math and I don't think it should be considered a bad thing.

Anytime you use while, do while and for loops you should be weary that you may cause a never ending loop. Same with recursion. Hence the reason why I asked the question ;)

As John stated however, in other languages you need to be especially careful. In some languages such as C you need to specify the size of arrays before you use them. If you fill it with too many values you'll start writing into memory space that isn't allocated which can cause all sorts of carnage. Hence the reason many PC users are very familiar with Blue Screens of Death.

Anyway, @tasairis, you wrote some really cool code. When that other guy asked that question I thought it would be simple. I think it took me about the same amount of time it took you to actually write the code though. Sometimes things that seem simple aren't. I'm glad you took the time to write that. Cool stuff.