PHP Random Shuffle Array Maintaining Key => Value - php

I've been looking on google for the answer but can't seem to find something fool-proof and cant really afford to mess this up (going live into a production site).
What I have is an advanced search with 20+ filters, which returns an array including an ID and a Distance. What I need to do is shuffle these results to display in a random order every time. The array I have that comes out at the moment is:
Array (
[0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
[1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
[2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
[3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
[4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
)
What I need to be able to do is randomise or order of these every time but maintain the id and distance pairs, i.e.:
Array (
[4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
[1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
[3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
[2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
[0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
)
Thanks :)

The first user post under the shuffle documentation:
Shuffle associative and
non-associative array while preserving
key, value pairs. Also returns the
shuffled array instead of shuffling it
in place.
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
Test case:
$arr = array();
$arr[] = array('id' => 5, 'foo' => 'hello');
$arr[] = array('id' => 7, 'foo' => 'byebye');
$arr[] = array('id' => 9, 'foo' => 'foo');
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));

As of 5.3.0 you could do:
uksort($array, function() { return rand() > rand(); });

Take a look to this function here :
$foo = array('A','B','C');
function shuffle_with_keys(&$array) {
/* Auxiliary array to hold the new order */
$aux = array();
/* We work with an array of the keys */
$keys = array_keys($array);
/* We shuffle the keys */`enter code here`
shuffle($keys);
/* We iterate thru' the new order of the keys */
foreach($keys as $key) {
/* We insert the key, value pair in its new order */
$aux[$key] = $array[$key];
/* We remove the element from the old array to save memory */
unset($array[$key]);
}
/* The auxiliary array with the new order overwrites the old variable */
$array = $aux;
}
shuffle_with_keys($foo);
var_dump($foo);
Original post here :
http://us3.php.net/manual/en/function.shuffle.php#83007

function shuffle_assoc($array)
{
$keys = array_keys($array);
shuffle($keys);
return array_merge(array_flip($keys), $array);
}

I was having a hard time with most of the answers provided - so I created this little snippet that took my arrays and randomized them while maintaining their keys:
function assoc_array_shuffle($array)
{
$orig = array_flip($array);
shuffle($array);
foreach($array AS $key=>$n)
{
$data[$n] = $orig[$n];
}
return array_flip($data);
}

Charles Iliya Krempeaux has a nice writeup on the issue and a function that worked really well for me:
function shuffle_assoc($array)
{
// Initialize
$shuffled_array = array();
// Get array's keys and shuffle them.
$shuffled_keys = array_keys($array);
shuffle($shuffled_keys);
// Create same array, but in shuffled order.
foreach ( $shuffled_keys AS $shuffled_key ) {
$shuffled_array[ $shuffled_key ] = $array[ $shuffled_key ];
} // foreach
// Return
return $shuffled_array;
}

Try using the fisher-yates algorithm from here:
function shuffle_me($shuffle_me) {
$randomized_keys = array_rand($shuffle_me, count($shuffle_me));
foreach($randomized_keys as $current_key) {
$shuffled_me[$current_key] = $shuffle_me[$current_key];
}
return $shuffled_me;
}
I had to implement something similar to this for my undergraduate senior thesis, and it works very well.

Answer using shuffle always return the same order. Here is one using random_int() where the order is different each time it is used:
function shuffle_assoc($array)
{
while (count($array)) {
$keys = array_keys($array);
$index = $keys[random_int(0, count($keys)-1)];
$array_rand[$index] = $array[$index];
unset($array[$index]);
}
return $array_rand;
}

$testArray = array('a' => 'apple', 'b' => 'ball', 'c' => 'cat', 'd' => 'dog');
$keys = array_keys($testArray); //Get the Keys of the array -> a, b, c, d
shuffle($keys); //Shuffle The keys array -> d, a, c, b
$shuffledArray = array();
foreach($keys as $key) {
$shuffledArray[$key] = $testArray[$key]; //Get the original array using keys from shuffled array
}
print_r($shuffledArray);
/*
Array
(
[d] => dog
[a] => apple
[c] => cat
[b] => ball
)
*/

I tried the most vote solution didn't popular shuffle list. This is the change I made to make it work.
I want my array key starting from 1.
$list = array_combine(range(1,10),range(100,110));
$shuffle_list = shuffle_assoc($list);
function shuffle_assoc($list)
{
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($list);
$random = array();
foreach ($keys as $k => $key) {
$random[$key] = $list[$k];
}
return $random;
}

Related

php making an assoc array in a for loop doesn't set the key [duplicate]

I've been looking on google for the answer but can't seem to find something fool-proof and cant really afford to mess this up (going live into a production site).
What I have is an advanced search with 20+ filters, which returns an array including an ID and a Distance. What I need to do is shuffle these results to display in a random order every time. The array I have that comes out at the moment is:
Array (
[0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
[1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
[2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
[3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
[4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
)
What I need to be able to do is randomise or order of these every time but maintain the id and distance pairs, i.e.:
Array (
[4] => Array ( [id] => 102 [distance] = 221.2212587899658 )
[1] => Array ( [id] => 13 [distance] => 4.75358968511882 )
[3] => Array ( [id] => 21 [distance] => 18.2155453552336 )
[2] => Array ( [id] => 7 [distance] => 33.2223233233323 )
[0] => Array ( [id] => 1 [distance] => 1.95124994507577 )
)
Thanks :)
The first user post under the shuffle documentation:
Shuffle associative and
non-associative array while preserving
key, value pairs. Also returns the
shuffled array instead of shuffling it
in place.
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
Test case:
$arr = array();
$arr[] = array('id' => 5, 'foo' => 'hello');
$arr[] = array('id' => 7, 'foo' => 'byebye');
$arr[] = array('id' => 9, 'foo' => 'foo');
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));
print_r(shuffle_assoc($arr));
As of 5.3.0 you could do:
uksort($array, function() { return rand() > rand(); });
Take a look to this function here :
$foo = array('A','B','C');
function shuffle_with_keys(&$array) {
/* Auxiliary array to hold the new order */
$aux = array();
/* We work with an array of the keys */
$keys = array_keys($array);
/* We shuffle the keys */`enter code here`
shuffle($keys);
/* We iterate thru' the new order of the keys */
foreach($keys as $key) {
/* We insert the key, value pair in its new order */
$aux[$key] = $array[$key];
/* We remove the element from the old array to save memory */
unset($array[$key]);
}
/* The auxiliary array with the new order overwrites the old variable */
$array = $aux;
}
shuffle_with_keys($foo);
var_dump($foo);
Original post here :
http://us3.php.net/manual/en/function.shuffle.php#83007
function shuffle_assoc($array)
{
$keys = array_keys($array);
shuffle($keys);
return array_merge(array_flip($keys), $array);
}
I was having a hard time with most of the answers provided - so I created this little snippet that took my arrays and randomized them while maintaining their keys:
function assoc_array_shuffle($array)
{
$orig = array_flip($array);
shuffle($array);
foreach($array AS $key=>$n)
{
$data[$n] = $orig[$n];
}
return array_flip($data);
}
Charles Iliya Krempeaux has a nice writeup on the issue and a function that worked really well for me:
function shuffle_assoc($array)
{
// Initialize
$shuffled_array = array();
// Get array's keys and shuffle them.
$shuffled_keys = array_keys($array);
shuffle($shuffled_keys);
// Create same array, but in shuffled order.
foreach ( $shuffled_keys AS $shuffled_key ) {
$shuffled_array[ $shuffled_key ] = $array[ $shuffled_key ];
} // foreach
// Return
return $shuffled_array;
}
Try using the fisher-yates algorithm from here:
function shuffle_me($shuffle_me) {
$randomized_keys = array_rand($shuffle_me, count($shuffle_me));
foreach($randomized_keys as $current_key) {
$shuffled_me[$current_key] = $shuffle_me[$current_key];
}
return $shuffled_me;
}
I had to implement something similar to this for my undergraduate senior thesis, and it works very well.
Answer using shuffle always return the same order. Here is one using random_int() where the order is different each time it is used:
function shuffle_assoc($array)
{
while (count($array)) {
$keys = array_keys($array);
$index = $keys[random_int(0, count($keys)-1)];
$array_rand[$index] = $array[$index];
unset($array[$index]);
}
return $array_rand;
}
$testArray = array('a' => 'apple', 'b' => 'ball', 'c' => 'cat', 'd' => 'dog');
$keys = array_keys($testArray); //Get the Keys of the array -> a, b, c, d
shuffle($keys); //Shuffle The keys array -> d, a, c, b
$shuffledArray = array();
foreach($keys as $key) {
$shuffledArray[$key] = $testArray[$key]; //Get the original array using keys from shuffled array
}
print_r($shuffledArray);
/*
Array
(
[d] => dog
[a] => apple
[c] => cat
[b] => ball
)
*/
I tried the most vote solution didn't popular shuffle list. This is the change I made to make it work.
I want my array key starting from 1.
$list = array_combine(range(1,10),range(100,110));
$shuffle_list = shuffle_assoc($list);
function shuffle_assoc($list)
{
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($list);
$random = array();
foreach ($keys as $k => $key) {
$random[$key] = $list[$k];
}
return $random;
}

Count how many times a value appears in this array?

I have this php array named $ids:
Array (
[0] => Array ( [id] => 10101101 )
[1] => Array ( [id] => 18581768 )
[2] => Array ( [id] => 55533322 )
[3] => Array ( [id] => 55533322 )
[4] => Array ( [id] => 64621412 )
)
And I need to make a new array containing each $ids id value, as the new keys, and the times each one appears, as the new values.
Something like this:
$newArr = array(
10101101 => 1,
18581768 => 1,
55533322 => 2,
64621412 => 1,
);
This is what I have:
$newArr = array();
$aux1 = "";
//$arr is the original array
for($i=0; $i<count($arr); $i++){
$val = $arr[$i]["id"];
if($val != $aux1){
$newArr[$val] = count(array_keys($arr, $val));
$aux1 = $val;
}
}
I supose array_keys doesn't work here because $arr has the id values in the second dimension.
So, how can I make this work?
Sorry for my bad english and thanks.
array_column will create an array of all the elements in a specific column of a 2-D array, and array_count_values will count the repetitions of each value in an array.
$newArr = array_count_values(array_column($ids, 'id'));
Or do it by hand like this where $arr is your source array and $sums is your result array.
$sums = array();
foreach($arr as $vv){
$v = $vv["id"];
If(!array_key_exists($v,$sums){
$sums[$v] = 0;
}
$sums[$v]++;
}
You can traverse your array, and sum the id appearance, live demo.
$counts = [];
foreach($array as $v)
{
#$counts[$v['id']] += 1;
}
print_r($counts);

Iterating a Multidimensional Array

I'm having trouble correctly iterating a multi-dimension array I am trying to retrieve the values for each well..value.
My Issue is I seem to have an array within an array which has an array for each key/pair value, I'm unsure how to loop through these and add the values to the database for each array.
Eg, if I have one form on my page the array return is below and further below that is what is returned with two forms etc
Array
(
[0] => Array
(
[0] => Array
(
[name] => sl_propid
[value] => 21
)
[1] => Array
(
[name] => sl_date
[value] => 04/01/2014
)
[2] => Array
(
[name] => sl_ref
[value] => Form1
)
[3] => Array
(
[name] => sl_nom_id
[value] => 12
)
[4] => Array
(
[name] => sl_desc
[value] => Form1
)
[5] => Array
(
[name] => sl_vat
[value] => 60
)
[6] => Array
(
[name] => sl_net
[value] => 999
)
)
)
My question is how do I iterate through the returned array no matter it's size and pull back each value?
I have tried nesting foreach loops, which did give me results, but only for one key/value pair which leads me to believe I'm doing the looping wrong, I can retrieve the values if I statically access them, which is of course no use normally.
foreach ($result as $array) {
print_r($array);
}
the above foreach returns the above arrays, adding another foreach removes the out "container" array but adding another foreach loop, returns only one key/value pair, which sort makes sense because the first index is an array, too, hope I haven't confused everyone else as much as already have myself D:.
Thank you for reading
Any help appreciated.
EDIT Using the below array walk recursive I get the output
$result = $this->input->post();
function test_print($item, $key)
{
echo "$key holds $item\n";
//$this->SalesLedgerModel->addInvoiceToLedger($key, $key, $key, $key, $key, $key, $key);
}
array_walk_recursive($result, 'test_print');
}
Which is almost what I want but how do I take each individual value and add it to my ModelFunction (to actually input the data to DB)
The function takes 7 parameters but I am unsure how to make sure the right info goes to the correct parameter
$this->SalesLedgerModel->addInvoiceToLedger($propid, $date, $ref, $nomid, $desc, $vat, $net);
My Controller function
function addInvoiceToLedger(){
$this->load->model('SalesLedgerModel');
// $propid = $this->input->post('propid');
// $date = $this->input->post('date');
// $ref = $this->input->post('ref');
// $nomid = $this->input->post('id');
// $desc = $this->input->post('desc');
// $vat = $this->input->post('vat');
// $net = $this->input->post('sl_net');
$results = $this->input->post();
//var_dump($results);
$size1 = sizeof($results)-1;
for($i=0; $i<=$size1; $i++)
{
$size2 = sizeof($results[$i])-1;
for($j=0; $j<=$size2; $j++)
{
$name = $results[$i][$j]['name'];
$value = $results[$i][$j]['value'];
echo $value . "\n" ;
$this->SalesLedgerModel->addInvoiceToLedger($value, $value, $value, $value, $value, $value, $value);
}
}
My Model function
function addInvoiceToLedger($propid, $date, $ref, $nomid, $desc, $vat, $net){
$data = array('sl_prop_id' => $propid, 'sl_date' => $date,
'sl_ref' => $ref, 'sl_nominal_sub' => $nomid, 'sl_invoice_desc' => $desc, 'sl_vat' => $vat, 'sl_amount' => $net);
$this->db->insert('salesledger', $data);
}
You can either write some recursive code to step through the array and call itself again if an element turns into an array, or write a very simple function and call it via array walk recursive which will then let you do whatever you like with the value:
<?php
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
function test_print($item, $key)
{
echo "$key holds $item\n";
}
array_walk_recursive($fruits, 'test_print');
?>
Output:
a holds apple
b holds banana
sour holds lemon
Try this. It'll be much faster. Since 3 foreach loops is much costlier than 2 for loops (for loops are faster than foreach loops) -
$size1 = sizeof($results)-1;
if($size1 > 0)
{
for($i=0; $i<=$size1; $i++)
{
$size2 = sizeof($results[$i])-1;
if($size2 > 0)
{
for($j=0; $j<=$size2; $j++)
{
$name = $results[$i][$j]['name'];
$value = $results[$i][$j]['value'];
$insert = $this->your_model->insert($name, $value);
}
}
}
}
foreach ($result as $array) {
foreach($array as $arr){
foreach($arr as $a){
echo $a[value];
}
}
}

PHP Sort Mega-Array by Value

I am looking for some advices how could I sort this kind of Array by 'variant_name' key.
Because Array is really huge I minified it to the looking result state.
...
$filter[2413][1][81][sub_id] = 1;
$filter[2413][1][81][variant_id] = 81;
$filter[2413][1][81][variant_name] = 'Banana';
$filter[2413][2][87][sub_id] = 2;
$filter[2413][2][87][variant_id] = 87;
$filter[2413][2][87][variant_name] = 'Apple';
$filter[2413][3][32][sub_id] = 3;
$filter[2413][3][32][variant_id] = 32;
$filter[2413][3][32][variant_name] = 'Carrot';
...
Keys $filter[x][x][x] are not sequential.
I have tried the sort function I used before but it doesn't work with this kind of Array:
function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
$sort_col = array();
foreach ($arr as $key=> $row) {
$sort_col[$key] = $row[$col];
}
array_multisort($sort_col, $dir, $arr);
}
array_sort_by_column($filter[][][], 'variant_name');
My target is modify array by sorting 'variant_name' to 'Apple', 'Banana', 'Carrot' accordingly keeping the array structure.
It's a working code tested from given examples.
Note that my codes still can be optimized, etc. Just take it as my advice.
TL;DR = Use usort().
function mySort($a,$b)
{
$av = "";
$bv = "";
foreach($a as $ak)
$av = $ak['variant_name'];
foreach($b as $bk)
$bv = $bk['variant_name'];
if($av[0] < $bv[0])
return false;
else return true;
}
How to use it? You have to specify which first level array to sort.
usort($filter['2413'],"mySort");
Then the result I got is:
Array
(
[2413] => Array
(
[0] => Array
(
[87] => Array
(
[sub_id] => 2
[variant_id] => 87
[variant_name] => Apple
)
)
[1] => Array
(
[81] => Array
(
[sub_id] => 1
[variant_id] => 81
[variant_name] => Banana
)
)
[2] => Array
(
[32] => Array
(
[sub_id] => 3
[variant_id] => 32
[variant_name] => Carrot
)
)
)
)

Multidimensional array unique based on value (not array key) [duplicate]

This question already has answers here:
How can you make a multidimensional array unique? [duplicate]
(6 answers)
Closed 10 years ago.
I have a multidimensional array which I need to be sorted with uniqueness as I have duplicated records, so I need array_unique to go through the array and remove duplicates by the value, e.g.
Array
(
[0] => Array
(
[id] => 324
[time_start] => 1301612580
[level] => 0.002
[input_level] => 0.002
)
[1] => Array
(
[id] => 325
[time_start] => 1301612580
[level] => 0.002
[input_level] => 0.002
)
[2] => Array
(
[id] => 326
[time_start] => 1301612580
[level] => 0.002
[input_level] => 0.002
)
)
There are duplicated time_start, which they are all the same, also level and input_level but they are not to be affected, only if there are matching time_start it should remove it and process the whole array (the array is bigger than you think, but I just posted a small example of the array). Should remove dupes and return like this:
Array
(
[0] => Array
(
[id] => 324
[time_start] => 1301612580
[level] => 0.002
[input_level] => 0.002
)
)
Questions I've found that didn't work:
reformat multidimensional array based on value
Delete element from multidimensional-array based on value
$input = array( /* your data */ );
$temp = array();
$keys = array();
foreach ( $input as $key => $data ) {
unset($data['id']);
if ( !in_array($data, $temp) ) {
$temp[] = $data;
$keys[$key] = true;
}
}
$output = array_intersect_key($input, $keys);
or
$input = array( /* your data */ );
$temp = $input;
foreach ( $temp as &$data ) {
unset($data['id']);
}
$output = array_intersect_key($input, array_unique($temp));
$temp = array();
array_filter($yourArray, function ($v) use (&$temp) {
if (in_array($v['time_start'], $temp)) {
return false;
} else {
array_push($temp, $v['time_start']);
return true;
}
});
Uses array_filter() which will filter an array based on the result of a callback (I used an anonymous function which can be used since PHP 5.3). The time_start values are collected into a temporary array.
I think you'll just have to walk it:
$usedVals = array();
$outArray = array();
foreach ($targetArray as $arrayItem)
{
if (!in_array($arrayItem['time_start'],$usedVals))
{
$outArray[] = $arrayItem;
$usedVals[] = $arrayItem['time_start'];
}
}
return $outArray;
$uniq = array();
foreach($no_unique as $k=>$v) if(!isset($uniq[$v['time_start']])) $uniq[$v['time_start']] = $v;
$uniq = array_values($uniq);

Categories