Shuffle 2 php arrays in the same way - php

I have this for example:
$array['one'][0] = 0;
$array['one'][1] = 1;
$array['one'][2] = 2;
$array['one'][3] = 3;
$array['two'][0] = 00;
$array['two'][1] = 11;
$array['two'][2] = 22;
$array['two'][3] = 33;
How can I shuffle them both to get something like:
$array['one'][0] = 2;
$array['one'][1] = 1;
$array['one'][2] = 3;
$array['one'][3] = 0;
$array['two'][0] = 22;
$array['two'][1] = 11;
$array['two'][2] = 33;
$array['two'][3] = 00;
Or any other random order, but having the same "random factor" in both?
For example, I want that $array['one'][0] and $array['two'][0] get shuffled to get $array['one'][x] and $array['two'][x] (x being a random key, but the SAME on both arrays).

$count = count($array['one']);
$order = range(1, $count);
shuffle($order);
array_multisort($order, $array['one'], $array['two']);
Works with arrays with elements of any type (objects and arrays too).
This way may by used with any number of arrays (not only two).
Works with duplicated values.
Clean code.

Something like this could work. It's similar to Mimikry's answer except this one will work even if you happen to have duplicate values in array one (this one doesn't use values of array one as keys of the temporary array).
Assuming both arrays are of the same size.
$c = count($array['one']);
$tmp = array();
for ($i=0; $i<$c; $i++) {
$tmp[$i] = array($array['one'][$i], $array['two'][$i]);
}
shuffle($tmp);
for ($i=0; $i<$c; $i++) {
$array['one'][$i] = $tmp[$i][0];
$array['two'][$i] = $tmp[$i][1];
}

hopefully i get you right.
For your example above, this code should work. But it's pretty hacky...
$array['one'][0] = 'A';
$array['one'][1] = 'B';
$array['one'][2] = 'C';
$array['one'][3] = 'D';
$array['two'][0] = 'AA';
$array['two'][1] = 'BB';
$array['two'][2] = 'CC';
$array['two'][3] = 'DD';
// save the dependencies in tmp array
foreach ($array['two'] as $key => $val) {
$tmp[$array['one'][$key]] = $val;
}
shuffle($array['one']);
// restore dependencies in tmp2 array
foreach ($array['one'] as $key => $val) {
$tmp2[$key] = $tmp[$val];
}
// overwrite with restore array
$array['two'] = $tmp2;
var_dump($array):
array(2) {
["one"]=>
array(4) {
[0]=>
string(1) "B"
[1]=>
string(1) "A"
[2]=>
string(1) "C"
[3]=>
string(1) "D"
}
["two"]=>
array(4) {
[0]=>
string(2) "BB"
[1]=>
string(2) "AA"
[2]=>
string(2) "CC"
[3]=>
string(2) "DD"
}
}

The best practice, imho, is as follows:
$tmp = array_combine($array['one'],$array['two']);
shuffle($tmp);
$array['one'] = array_keys($tmp);
$array['two'] = array_values($tmp);
This is clear code and should be fast. No need to reinvent the wheel like in some other answers.

This isn't an example with multidimensional arrays but it works great for sorting multiple normal arrays the same way and with shuffle. Maybe it could be adapted for multidimensional arrays too. It does assume all arrays are the same length.
$array_count = count($array_1);
for($i=0;$i<=($array_count-1);$i++){
$temp_array[$i] = $i;
}
shuffle($temp_array);
for($i=0;$i<=($array_count-1);$i++){
$o = $temp_array[$i];
$array_1_sorted[$i]=$array_1[$o];
$array_2_sorted[$i]=$array_2[$o];
$array_3_sorted[$i]=$array_3[$o];
}
This will give you new arrays which are all sorted the same random way. You could then set the old arrays equal to the new ones or keep them in-tact.

Not sure exactly what you are trying to do, but your best bet is probably to put array 1 and array 2 into a multi-dimensional array and then random the primary array. That will give you a random arrangement of values, but within each key will be the values of each array. We could give you more specific answers if you can provide a bit more detail of exactly what you are doing.

Related

Convert single array into multidimensional array in PHP?

If I have this array in PHP:
array(3) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
[2]=>
string(5) "third"
}
How can I convert this single array into a multidimensional array? What is the quickest way? So I can access this array like:
$array["first"]["second"]...
I want to be able to then set a value to this index like:
$array["first"]["second"]["third"] = "example";
I thought that I need a for loop or a recursive function but I have no idea how to start.
It wasn't quite as simple as I had imagined to begin with. The key to it was doing the process backwards - starting with the last array and then wrapping it in more arrays until you get back to the top level.
$array = array("first", "second", "third");
$newArr = array();
//loop backwards from the last element
for ($i = count($array)-1; $i >= 0 ; $i--)
{
$arr = array();
if ($i == count($array)-1) {
$val = "example";
$arr[$array[$i]] = $val;
}
else {
$arr[$array[$i]] = $newArr;
}
$newArr = $arr;
}
var_dump($newArr);
echo "-------".PHP_EOL;
echo $newArr["first"]["second"]["third"];
Demo: http://sandbox.onlinephpfunctions.com/code/0d7fa30fde7126160fbcc0e80e5727f17b19e39f

How to optimize multiple if check for array index check and initialize value 1

I have a string which has "23:22:0"
$string = "23:22:0";
$array = explode(":", $string);
if ($array[0] == 0) {
$array[0] = 1;
}
if ($array[1] == 0) {
$array[1] = 1;
}
if ($array[2] == 0) {
$array[2] = 1;
}
How to avoid multiple if condition check here and i need this condition to be optimised in some best way. Any help is appreciated thanks in advance.
Please check below example. I have commented out your $string variable and tested $string with '0:0:0' value.
Added print_r() to check whether the value is correct or not as we are expecting.
Hope it might be helpful.
//$string = "23:22:0";
$string = "0:0:0";
$array = explode(":", $string);
$array = array(
0 => ($array[0] == 0) ? 1 : $array[0],
1 => ($array[1] == 0) ? 1 : $array[1],
2 => ($array[2] == 0) ? 1 : $array[2],
);
print_r($array);
I wrote this answer because I thought there was an unknown number of items.
OP has now clarified that it's always three items. This is probably a bit overkill for the task at hand.
You can create a new array with 1's and use array_replace to merge it with the original array if you first remove the zero values.
$string = "23:22:0";
$array = explode(":", $string);
$fill = array_fill(0,count($array), 1); //create new array [1,1,1]
$array= array_filter($array); // remove zero values
$array= array_replace($fill,$array); // "merge" the arrays
var_dump($array);
Output:
array(3) {
[0]=>
string(2) "23"
[1]=>
string(2) "22"
[2]=>
int(1)
}
https://3v4l.org/thpfU
With three items in mind you can make the code look better with a loop.
It will perform about the same I believe.
foreach($array as &$val){
if(!$val) $val=1;
}

Changing values of multidimensional array php

Its my first time working with multidimensional arrays in php. I need to change the second number in each sub array.
What I want is to check if the Id in the array matches the Id from the database. When the two match I want to change the 2nd entry in the sub array by adding a number to it. If the Id from the query does not match anything in the list I want a new sub array to be pushed to the end of the array with the values of Id and points_description.
Also, if its helpful, my program right now does find the matches. The only thing is, it does not update the 2D array.
$array = array(array());
while ($row_description = mysqli_fetch_array($query_description)) {
$check = 1;
$is_match = 0;
foreach ($array as $i) {
foreach ($i as $value) {
if ($check == 1) {
if ($row_description['Id'] == $value) {
//$array[$i] += $points_description;
$is_match = 1;
}
}
$check++;
$check %= 2; //toggle between check and points
}
}
if ($is_match == 0) {
array_push($array, array($row_description['Id'], $points_description));
}
}
I feel like Im doing this so wrong. I just want to go through my 2D array and change every second value. The expected output should be a print out of all the Ids and their corresponding point value
I hope this is helpful enough.
Example: $row_description['Id'] = 2 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1))
if $row_description['Id'] = 3 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1),array(3,3))
By default PHP will copy an array when you use it in a foreach.
To prevent PHP from creating this copy you need to use to reference the value with &
Simple example :
<?php
$arrFoo = [1, 2, 3, 4, 5,];
$arrBar = [3, 6, 9,];
Default PHP behavior : Make a copy
foreach($arrFoo as $value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
*/
ByReference : Don't create the copy :
foreach($arrFoo as &$value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(162)
[1]=>
int(324)
[2]=>
int(486)
[3]=>
int(648)
[4]=>
&int(810)
}
*/

Convert 2 pairs in array to getassociative array

The title of this questions sounds a bit confusing, but I don't know how I should call it, so I will explain it further:
For example I got the following array:
[0]=> "id" [1]=> "5" [2]=> "value" [3]=> "8"
And so on, this array could be endless, but the number of content is even.
Now I want to have this array converted into an associative array where on pair is index => value. Like this:
[id] = "5" [value] = "8"
I thought about, that I foreach the array twice: first I set the indexes if count is odd and second I reset index and set the value if count is even. But there must be a better approach to do this.
Thanks for you help.
$array = array("id", "5", "value", "8");
$new_array = array();
for ($i = 1; $i < count($array); $i+=2) {
$new_array[$array[$i - 1]] = $array[$i];
}
The following code should serve your purpose:
$arr = array("id", "5", "value", "8");
$size = sizeof($arr);
$_arr = array();
for($i = 0; $i < $size; $i+=2){
$_arr[$arr[$i]] = $arr[$i+1];
}
DEMO
Why not a multidimensional array?
$arr = array(
array("id", "5"),
array("value", "8")
);

Random But Unique Pairings, with Conditions

I need some help/direction in setting up a PHP script to randomly pair up items in an array.
The items should be randomly paired up each time.
The items should not match themselves ( item1-1 should not pair up with item1-1 )
Most of the items have a mate (ie. item1-1 and item1-2). The items should not be paired with their mate.
I've been playing around with the second script in this post but, I haven't been able to make any progress. Any help is appreciated.
Very simple approach, but hopefully helpful to you:
(mates, if grouped in an array (e.g. array('a1', 'a2')), will not be paired.)
function matchUp($array) {
$result = array();
while($el = array_pop($array)) {
shuffle($array);
if (sizeof($array) > 0) {
$candidate = array_pop($array);
$result[] = array(
array_pop($el),
array_pop($candidate)
);
if (sizeof($el) > 0) {
$array[] = $el;
}
if (sizeof($candidate) > 0) {
$array[] = $candidate;
}
}
else {
$result[] = array(array_pop($el));
}
}
return $result;
}
$array = array(
array('a1', 'a2'),
array('b1', 'b2'),
array('c1'),
array('d1'),
array('e1', 'e2'),
array('f1'),
array('g1', 'g2'),
);
Update:
foreach(matchUp($array) as $pair) {
list($a, $b) = $pair + array(null, null);
echo '<div style="border: solid 1px #000000;">' . $a . ' + ' . $b . '</div>';
}
With the randomness, there is no guarantee that a full correct solution will be reached.
Certain problem sets are more likely to be solved than others. Some will be impossible.
You can configure how many times it will try to achieve a good solution. After the specified number of tries it will return the best solution it could find.
function pairUp (array $subjectArray) {
// Config options
$tries = 50;
// Variables
$bestPaired = array();
$bestUnpaired = array();
for($try = 1; $try <= 50; $try++) {
$paired = array();
$unpaired = array();
$toBePaired = $subjectArray;
foreach($subjectArray as $subjectIndex => $subjectValue) {
// Create array without $thisValue anywhere, from the unpaired items
$cleanArray = array();
foreach($toBePaired as $index => $value) {
if($value != $subjectValue) {
array_push($cleanArray, array(
'index' => $index,
'value' => $value
));
}
}
sort($cleanArray); // reset indexes in array
// See if we have any different values left to match
if(count($cleanArray) == 0) {
array_push($unpaired, $subjectValue);
continue;
}
// Get a random item from the clean array
$randomIndex = rand(0,count($cleanArray)-1);
// Store this pair
$paired[$subjectIndex] = $subjectValue . '-' . $cleanArray[$randomIndex]['value'];
// This item has been paired, remove it from unpairedItems
unset($toBePaired[$cleanArray[$randomIndex]['index']]);
sort($toBePaired);
}
// Decide if this is our best try
if(count($paired) > count($bestPaired)) {
$bestPaired = $paired;
$bestUnpaired = $unpaired;
}
// If we had no failures, this was a perfect try - finish
if(count($unpaired) == 0) { $break; }
}
// We're done, send our array of pairs back.
return array(
'paired' => $bestPaired,
'unpaired' => $bestUnpaired
);
}
var_dump(pairUp(array('a','b','c','d','e','a','b','c','d','e')));
/*
Example output:
array(2) {
["paired"]=>
array(10) {
[0]=>
string(3) "a-b"
[1]=>
string(3) "b-c"
[2]=>
string(3) "c-d"
[3]=>
string(3) "d-e"
[4]=>
string(3) "e-a"
[5]=>
string(3) "a-b"
[6]=>
string(3) "b-e"
[7]=>
string(3) "c-d"
[8]=>
string(3) "d-c"
[9]=>
string(3) "e-a"
}
["unpaired"]=>
array(0) {
}
}
*/
Case 1: if all elements had a mate
If all elements had a mate, the following solution would work, although I don't know if it would be perfectly random (as in, all possible outputs having the same probability):
Shuffle the list of elements, keeping mates together
original list = (a1,a2),(b1,b2),(c1,c2),(d1,d2)
shuffled = (c1,c2),(d1,d2),(a1,a2),(b1,b2)
Shift the second mate to the right. The matches have been formed.
shifted = (c1,b2),(d1,c2),(a1,d2),(b1,a2)
(Edit1: if applied exactly as described, there is no way a1 ends up matched with b1. So, before shifting, you may want to throw a coin for each pair of mates to decide whether they should change their order or not.)
Case 2: if only some elements have a mate
Since in your question only some elements will have a mate, I guess one could come up with the following:
Arbitrarily pair up those elements who don't have a mate. There should be an even number of such elements. Otherwise, the total number of elements would be odd, so no matching could be done in the first place.
original list = (a1,a2),(b1,b2),c1,d1,e1,f1 // c1,d1,e1 and f1 don't have mates
list2 = (a1,a2),(b1,b2),(c1,d1),(e1,f1) // pair them up
Shuffle and shift as in case 1 to form the matches.
shuffled = (e1,f1),(a1,a2),(c1,d1),(b1,b2)
shifted = (e1,b2),(a1,f1),(c1,a2),(b1,d1)
Again, I don't know if this is perfectly random, but I think it should work.
(Edit2: simplified the solution)
(Edit3: if the total number of elements is odd, someone will be left without a match, so pick an element randomly at the beginning to leave it out and then apply the algorithm above).

Categories