Shuffle an array of Q&A pairs - php

What is the best way you think to shuffle a multi-dimensional array in the following structure, so that question-answer pairs are separated?
$myArray = array(
array('question' => 'q1', 'answer' => 'a1'),
array('question' => 'q2', 'answer' => 'a2'),
array('question' => 'q3', 'answer' => 'a3')
//...
//...
);
What I need is to turn this:
q1-a1, q2-a2, q3-a3...
into this:
q3-a2, q4-a3, q1-a9...
I get this array from a questions database. I want to display question-answer pairs but shuffled obviously. I have a few solutions in my mind, just curious for clever ways to do it ;)

Well you could just simply get the questions and answers, shuffle them, then reapply:
$q = $a = array();
foreach ($myArray as $value) {
$q[] = $value['question'];
$a[] = $value['answer'];
}
shuffle($q);
shuffle($a);
foreach($myArray as $key => &$value) {
$value['question'] = $q[$key];
$value['answer'] = $a[$key];
}
echo '<pre>';
print_r($myArray);
You could also use array_collumn() if available (PHP 5 >= 5.5.0):
$q = array_column($myArray, 'question');
$a = array_column($myArray, 'answer');

PHP has a plethora amount of built-in array functions. Using a combination of these functions, you could create a custom shuffle function that uses array_keys, array_values, shuffle and array_combine internally. Try the following:
// Create a copy of the original array to key
// for processing later...
$originalArray = $myArray;
function shuffleAll($myArray) {
// Pull the keys into an array and
// pull the values into another
// array...
$keys = array_keys($myArray);
$values = array_values($myArray);
// Shuffle the arrays independently...
shuffle($keys);
shuffle($values);
// Combine the arrays into one...
return array_combine($keys, $values);
}
$myArray = shuffleAll($myArray);
$myArray should now have a custom assortment of your now non-matching key-value pairs. The original values have been preserved in $originalArray for latter processing and matching.
References:
array_combine(...)
array_keys(...)
array_values(...)
shuffle(...)

Related

Why does the array_push() "deepen" the depth of an array?

I have a two dimensional array, lets call it BASE.
Now I wanto to iterate over this array with a foreach loop, and each time push the currently selected array into a new array.
foreach($BASE as $array){
$newarray = [];
array_push($newarray, $array);
$newarraylength = count($newarray[0])
//some more code
}
This way, I want to accomplish being able to iterate over the pushed array inside a for-loop nested inside this foreach loop, like this
for(index = 0; index < $newarraylength; $index++){
newarray[0][index]
}
However, when the array from the BASE array is pushed into the new array, this new array for some reason becomes threedimensional Oo
Therefore, the syntax above doesn't work.
So, either someone of you please tell me how to deal with looping through this threedimensional array. Because my head doesn't manage to find a solution to this.
Or someone please tell me how to push a 1-dimensional array into another 1-dimensional, still empty array, without creating a 3-dimensional array.
I believe what you want to do is:
foreach($BASE as $array){
$newarray = [];
array_push($newarray, $array);
$newarraylength = count($newarray[0])
//some more code
}
What you've done is to push the whole two dimensional array.
So if $BASE is:
array(
'1' => array('a', 'b'),
'2' => array('c', 'd')
)
Then pushing that to $newarray would result in
$newarray =
array(
0 => array(
'1' => array('a', 'b'),
'2' => array('c', 'd')
)
);
what you are basically trying to achieve is:
foreach($BASE as $array){
$newarray = [];
array_push($newarray, $array);
$newarraylength = count($newarray[0])
//some more code
for(index = 0; index < $newarraylength; $index++){
//your code with newarray[0][index] here
}
}
but could use two nested foreach
foreach($BASE as $array){
foreach($array as $key=>$value){
}
}
keep in mind that the first method will only work with non associative array...

Individually sorting subarrays of an array in PHP

I have an array of numeric subarrays. I want to sort all the subarrays, and then sort the whole array, and remove duplicates. Using sort($val) doesn't work, so I found the following workaround with $derp, which I find insanely stupid:
$arr = array( array(5,6), array(1,2), array(6,5) );
foreach ($arr as $key => $val) {
$derp = $val;
sort($derp);
$arr[$key] = $derp;
}
sort($arr);
$arr = array_map("unserialize", array_unique(array_map("serialize", $arr)));
The result is array( array(1,2), array(5,6) ). Is that is the correct way to do this in PHP, or is there a better and shorter way?
I created a pastebin as a response to the first answer: pastebin.com/Y5vNvKKL
This question is not anymore just about a less goofy way to write this: Now the question is:Why does sort() in array_work() not give the same result as sort() in foreach?
By the way: This is about finding the partitions of multisets.
I'd approach it like this:
array_walk($arr, 'sort');
$deduped = array();
foreach ($arr as $val) {
$deduped[serialize($val)] = $val;
}
$arr = array_values($deduped);

Storing array data in foreach loop in PHP

I am wondering how can I store all values from a foreach loop, I know that I am re-initialising in the loop but I'm not sure how to store the data. Heres my basic loop:
$array = array("v1", "v2", "v3", "v4");
foreach($array as $row){
$arr = array('val' => $row);
echo $row;
}
print_r($arr);
So when I use the print_r($arr) the only thing outputted would be v4 and I know that the values are there because the echo $row; does return each output individually.
My question would be how can I store each instance of row in my array?
Create a new array, fill it:
$array = array("v1", "v2", "v3", "v4");
$newArray = array();
foreach($array as $row){
// notice the brackets
$newArray[] = array('val' => $row);
}
print_r($newArray);
It looks like you are storing your array wrong.
Try adjusting the $arr = array('val' => $row);
to:
$arr[] = array('val' => $row);
This will set it so you pick up each line as a separate array which you can easily navigate through.
Hope this helps!
If I'm reading correctly, you want to transform your array from simple values to key-value pairs of 'val'->number. array_map is a concise way of doing this sort of transformation.
$array = array("v1", "v2", "v3", "v4");
$arr = array_map(function($v) { return array('val'=>$v); }, $array);
print_r($arr);
While it doesn't matter in this case, array_map also has the handy feature of preserving your keys, in case that is desired.
Note that you can also provide a named function to array_map, instead of providing the implementation inline, which can be nice in the event that your transform method gets more complicated. More on array_map here.

how to get keys that correspond to different values in two arrays?

$arr1 = array('potato'=>1,'tomato'=>2,'apple'=>5,'banana'=>10);
$arr2 = array('orange'=>20,'tomato'=>3,'apple'=>5,'banana'=>20);
I need function that would return array('tomato','banana'), consider that it omits keys that don't exist in one or the other array. Apple has the same value in both arrays, so it should be omitted - returned should be only keys whose values differ and are set
This should work (demo):
$arr1 = array('potato'=>1,'tomato'=>2,'apple'=>5,'banana'=>10);
$arr2 = array('orange'=>20,'tomato'=>3,'apple'=>5,'banana'=>20);
$result = array_keys(array_diff(array_intersect_key($arr1, $arr2), $arr2));
print_r($result);
Output:
Array
(
[0] => tomato
[1] => banana
)
Reference:
array_intersect_key — Computes the intersection of arrays using keys for comparison
array_diff — Computes the difference of arrays
array_keys — Return all the keys or a subset of the keys of an array
$array3 = array();
foreach(array_intersect_key($array1, $array2) as $key => $v){
if($array1[$key] != $array2[$key]) $array3[] = $key;
}
<?php
/**
* Returns an array which contains keys which are in both $array1
* and $array2, and which have different values.
*/
function getKeysWhichMatchAndHaveDifferentValues($array1, $array2)
{
$arrIntersected = array_intersect_key($array1, $array2);
foreach($arrIntersected as $key => $value)
{
if($array2[$key] == $value) {
unset($arrIntersected[$key]);
}
}
return array_keys($arrIntersected);
}
$arr1 = array('potato'=>1,'tomato'=>2,'apple'=>5,'banana'=>10);
$arr2 = array('orange'=>20,'tomato'=>3,'apple'=>5,'banana'=>20);
$final = getKeysWhichMatchAndHaveDifferentValues($arr1, $arr2);
echo '<pre>' . print_r($final) . '</pre>';
?>
I would do simple loop.
Of course if you will need to compare large arrays, the native PHP functions could help a lot. Still can't answer right now what would be the most optimal way to do this.
You could do this using array_intersect and array_keys.
$arr3 = array_intersect(array_keys($arr1), array_keys($arr2));

delete all values from an array while keeping keys intact

Do I really have to do this to reset an array?
foreach ($array as $i => $value) {
unset($array[$i]);
}
EDIT:
This one makes more sense, as the previous one is equivalent to $array=array();
foreach ($array as $i => $value) {
$array[$i]=NULL;
}
$keys = array_keys($array);
$values = array_fill(0, count($keys), null);
$new_array = array_combine($keys, $values);
Get the Keys
Get an array of nulls with the same number of elements
Combine them, using keys and the keys, and the nulls as the values
As comments suggest, this is easy as of PHP 5.2 with array_fill_keys
$new_array = array_fill_keys(array_keys($array), null);
Fill array with old keys and null values
$array = array_fill_keys(array_keys($array), null)
There is no build-in function to reset an array to just it's keys.
An alternative would be via a callback and array_map():
$array = array( 'a' => 'foo', 'b' => 'bar', 'c' => 'baz' );
With regular callback function
function nullify() {}
$array = array_map('nullify', $array);
Or with a lambda with PHP < 5.3
$array = array_map(create_function('', ''), $array);
Or with lambda as of PHP 5.3
$array = array_map(function() {}, $array);
In all cases var_dump($array); outputs:
array(3) {
["a"]=> NULL
["b"]=> NULL
["c"]=> NULL
}
Define this function and call it whenever you need it:
function erase_val(&$myarr) {
$myarr = array_map(create_function('$n', 'return null;'), $myarr);
}
// It's call by reference so you don't need to assign your array to a variable.
// Just call the function upon it
erase_val($array);
That's all!
Get the array keys, then use them to create a new array with NULL values:
array_fill_keys(array_keys($array), NULL);
About array_fill_keys():
The array_fill_keys() function fills an array with values, specifying keys.
About array_keys():
The array_keys() function returns all the keys of an array.
foreach($a as &$v)
$v = null;
The reasoning behind setting an array item to null is that an array needs to have a value for each key, otherwise a key makes no sense. That is why it is called a key - it is used to access a value. A null value seems like a reasonable choice here.
Wrap it in a [reusable] procedure:
function array_purge_values(&$a) {
foreach($a as &$v)
$v = null;
}
Keep in mind though that PHP versions 5.3 and those released later, pass values to functions by reference by default, i.e. the ampersand preceding argument variable in the function declaration is redundant. Not only that, but you will get a warning that the notion is deprecated.
If you need to nullify the values of a associative array you can walk the whole array and make a callback to set values to null thus still having keys
array_walk($ar,function(&$item){$item = null;});
In case if you need to nullify the whole array just reassign it to empty one
$ar = array();
unset would delete the key, You need to set the value to null or 0 as per your requirement.
Example
I don't get the question quite well, but your example
foreach ($array as $i => $value) {
unset($array[$i]);
}
is equivilent to
$array = array();
Why not making an array with required keys and asinging it to variable when you want reset it?
function resetMyArr(&$arr)
{
$arr = array('key1'=>null,'key2'=>null);
}
This is a fairly old topic, but since I referenced to it before coming up with my own solution for a more specific result, so therefore I will share with you that solution.
The desired result was to nullify all values, while keeping keys, and for it to recursively search the array for sub-arrays as well.
RECURSIVELY SET MULTI-LEVEL ARRAY VALUES TO NULL:
function nullifyArray(&$arrayData) {
if (is_array($arrayData)) {
foreach ($arrayData as $aKey => &$aValue) {
if (is_array($aValue)) {
nullifyArray($aValue);
} else {
$aValue = null;
}
}
return true; // $arrayData IS an array, and has been processed.
} else {
return false; // $arrayData is NOT an array, no action(s) were performed.
}
}
And here is it in use, along with BEFORE and AFTER output of the array contents.
PHP code to create a multilevel-array, and call the nullifyArray() function:
// Create a multi-level array.
$testArray = array(
'rootKey1' => 'rootValue1',
'rootKey2' => 'rootValue2',
'rootArray1' => array(
'subKey1' => 'subValue1',
'subArray1' => array(
'subSubKey1' => 'subSubValue1',
'subSubKey2' => 'subSubValue2'
)
)
);
// Nullify the values.
nullifyArray($testArray);
BEFORE CALL TO nullifyArray():
Array
(
[rootKey1] => rootValue1
[rootKey2] => rootValue2
[rootArray1] => Array
(
[subKey1] => subValue1
[subArray1] => Array
(
[subSubKey1] => subSubValue1
[subSubKey2] => subSubValue2
)
)
)
AFTER CALL TO nullifyArray():
Array
(
[rootKey1] =>
[rootKey2] =>
[rootArray1] => Array
(
[subKey1] =>
[subArray1] => Array
(
[subSubKey1] =>
[subSubKey2] =>
)
)
)
I hope it helps someone/anyone, and Thank You to all who previously answered the question.
And speed test
This test shows speed when clearing a large array
$a1 = array();
for($i=0;$i<=1000;$i++)
{
$a1['a'.$i] = $i;
}
$b = $a1;
$start_time = microtime(TRUE);
foreach ($a1 as $field => $val) {
$a1[$field]=NULL;
}
$end_time = microtime(TRUE);
$duration = $end_time - $start_time;
var_dump( $duration*1000 );
var_dump('all emelent of array is '.reset($a1));
$start_time = microtime(TRUE);
$allkeys = array_keys($b);
$newarray = array_fill_keys($allkeys, null);
$end_time = microtime(TRUE);
$duration = $end_time - $start_time;
var_dump( $duration*1000 );
var_dump('all emelent of array is '.reset($newarray));
Just do this:
$arrayWithKeysOnly = array_keys($array);
http://php.net/manual/en/function.array-keys.php
EDIT: Addressing comment:
Ok, then do this:
$arrayWithKeysProper = array_flip(array_keys($array));
http://www.php.net/manual/en/function.array-flip.php
EDIT: Actually thinking about it, that probably won't work either.

Categories