-1

I would like to get a random value from a multidimensional array. Some of the values are on the first level and some of the values are on the second level.

array_rand() only works on one level, so how can I randomly grab a value while considering all levels?

A sample array:

$array = [
    62,
    9,
    [5, 16, 45],
    [11, 21, 25, 32, 50],
    [4, 23, 37, 57],
    [13, 15, 18, 22, 27, 30]
];

I realize that if the array was flattened, it would be a much simpler task.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Jesper Kaae
  • 118
  • 1
  • 9
  • What code have you tried? "All sort" is broad –  Nov 05 '14 at 19:16
  • It's not even clear what you're trying to do... at first I thought you just wanted a random value from each index but then, where did `56` come from in the second array? please be more clear about what you're trying to accomplish. – I wrestled a bear once. Nov 05 '14 at 19:22
  • Adelphia what point does it have, where the "56" comes from? What i need is just taking a random value of that array? – Jesper Kaae Nov 05 '14 at 19:27

6 Answers6

1

Use is_array() inside a foreach() function to check and loop inside the inner array.

foreach($array as $piece) {
    if(is_array($piece){
        foreach($piece as $item)
            $newarray[] = $item;
    } else {
        $newarray[] = $piece;
    }
}

The $newarray[] variable contains all the elements that you need to perform rand. This should solve your issue.

I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116
cuSK
  • 809
  • 11
  • 26
0

You can use a recursive function

function compress_arr($arr, &$new_arr){
    foreach($arr as $val){
        if(is_array($val)){
            compress_arr($val, $new_arr);
        } else {
            $new_arr[] = $val;
        }
    }
}
$arr_n = array();
compress_arr($array, $arr_n);

Note that this function doesn't use return, as I pass by reference the array, it will modify the variable passed.

The rest of the logic is straightforward : we iterate over the array, if it's an other array then we call the function, causing it to iterate in again. Untill it's a value, then we add the val to the new array passed by ref. This function will compress into a single-array everything that is structured as nested array, regardless of the size of the number of sublevels.

If you don't like the pass by ref, you can modify it to this:

function compress_arr($arr){
    $arr_ret = array();
    foreach($arr as $val){
        if(is_array($val)){
            array_merge($arr_ret, compress_arr($val));
        } else {
            $arr_ret[] = $val;
        }
    }
    return $arr_ret;
}

And now to take a random value in that array, just use array_rand function. It will spare you length calculating with rand function...

0

Try this...

$flatarray = array();
foreach($orig_array as $ra)
{
   if ( is_array($ra) )
      $flatarray = array_merge($flatarray,$ra);
   else   
      array_push($flatarray,$ra);
}
dors
  • 1,152
  • 11
  • 19
0

You could use RecursiveIteratorIterator, RecursiveArrayIterator and iterator_to_array

Your code would then look like this:

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($vals));
$newArray  = iterator_to_array($iterator, false);
var_dump($newArray);

and it gives me this result:

array(20) {
  [0]=>
  int(62)
  [1]=>
  int(9)
  [2]=>
  int(5)
  [3]=>
  int(16)
  [4]=>
  int(45)
  [5]=>
  int(11)
  [6]=>
  int(21)
  [7]=>
  int(25)
  [8]=>
  int(32)
  [9]=>
  int(50)
  [10]=>
  int(4)
  [11]=>
  int(23)
  [12]=>
  int(37)
  [13]=>
  int(57)
  [14]=>
  int(13)
  [15]=>
  int(15)
  [16]=>
  int(18)
  [17]=>
  int(22)
  [18]=>
  int(27)
  [19]=>
  int(30)
}

We can now select a random value or values from the array like this:

$items = array_rand($newArray, 10);
var_dump($items);

Which would give us these 10 keys:

array(10) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(7)
  [6]=>
  int(9)
  [7]=>
  int(13)
  [8]=>
  int(14)
  [9]=>
  int(15)
}

We can then loop through those keys and get these values:

int(9)
int(5)
int(16)
int(45)
int(11)
int(25)
int(50)
int(57)
int(13)
int(15)

So in the end you can use this code:

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($vals));
$newArray = iterator_to_array($iterator, false);
$keys     = array_rand($newArray, 10);

foreach($keys as $key){
    var_dump($newArray[$key]);
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
0

You can use a simple recursive iterator & simple randomized value return class:

    class Randomizer
        {
            public  static $new;

            // Recursive iterator that stores array values in the $new variable
            public  static  function Combine($array = array())  {
                    foreach($array as $key => $value) {
                            if(!is_array($value)) {
                                    self::$new[]    =   $value;
                                }
                            else
                                self::Combine($value);
                        }

                    return self::$new;      
                }

            // Returns a randomized value
            public  static  function Fetch($arr)
                {
                    // Depending on needs, you could easily
                    // add shuffle, or other array functions
                    // otherwise you can just skip this method/function
                    $val    =   array_rand($arr);
                    return $val;
                }
        }

// If you had more advanced functions in the Fetch() class use this way
$test   =   Randomizer::Fetch(Randomizer::Combine($array));

// Or simply use
$test   =   array_rand(Randomizer::Combine($array));

print_r($test);
Rasclatt
  • 12,498
  • 3
  • 25
  • 33
0

From what I see, most answers are focussed on how to flatten a 2-dimensional array. I see that as an avoidable solution to an XY Problem.

More directly, you are seeking a recursive random value selecting function -- this is not an overly complex task. Just keep recursing while the randomly returned data is an array -- eventually you will be able to return the non-iterable value.

Code: (Demo)

function getRandomValueRecursive($array)
{
    $data = $array[array_rand($array)];
    if (is_array($data)) {
        $data = getRandomValueRecursive($data);
    }
    return $data;
}
var_export(getRandomValueRecursive($array));

Possible output:

32

All scalar values have a chance of being returned.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136