Compare Two Arrays based on key value - php

I'm working on a Quiz engine and am comparing answers.
I have two arrays
correct answers :
0 => "a"
1 => "a"
2 => "a"
3 => "c"
Chosen Answers...
0 => "c"
1 => "b"
2 => "a"
3 => "b"
So based on this, I know (from comparing myself) that I have 1 correct answer.
Is there a PHP function that can compare the keys and the values and increment a number of similar?
I've looked at array_intersect and array_difference but they don't seem to give me the desired answer.
Thanks

Short solution using array_intersect_uassoc function (on extended input arrays):
$correct = ["a", "a", "a", "c", "a", "c"];
$chosen = ["c", "b", "a", "b", "a", "b"];
$result = array_intersect_uassoc($correct, $chosen, 'strnatcmp');
print_r($result);
The output:
Array
(
[2] => a
[4] => a
)

I would write a function that would generate an array for each key and if the answer was correct (1, or 0 if wrong) that way you can not only quickly calculate the score but use the array to display the questionnaire result later. Like showing which questions were right and which ones were wrong.
<?php
$corrects = array(
0 => "a",
1 => "a",
2 => "a",
3 => "c"
);
$answers = array(
0 => "a",
1 => "a",
2 => "a",
3 => "c"
);
function verify($answers, $corrects) {
$results = array();
foreach($corrects as $question => $correct) {
$results[$question] = $correct == $answers[$question] ? 1 : 0;
}
return $results;
}
$results = verify($answers, $corrects);
$score = array_sum($results);
?>
It leaves room for more complex scoring or multi correct answer question etc.

Related

Array search multiple values in consecutive order

Take the given arrays:
// Original
array:14 [
0 => "hello"
1 => "i"
2 => "like"
3 => "cats"
4 => "they're"
5 => "cute"
6 => "and"
7 => "cuddly"
8 => "you"
9 => "know"
10 => "well"
11 => "i"
12 => "love"
13 => "cats"
]
// Sliced
array:6 [
0 => "like"
1 => "cats"
2 => "they're"
3 => "cute"
4 => "and"
5 => "cuddly"
]
I want to check the original array for my sliced values and retrieve their original keys. This must occur only when consecutive values match.
Ultimately, something like:
return array_keys_from_consec_values($original, $sliced);
// Result
array:14 [
0 => 2
1 => 3
2 => 4
3 => 5
4 => 6
5 => 7
]
Notes
sliced is not a result of using array_slice() on the original array. Otherwise I would have used that function and utilised the preserve keys parameter.
Want to avoid ambiguities. For example, a simple array_search for cats would return the key 3, but 13 also exists. Which might throw the function off.
In the event of any of the sliced values not existing in original (in order) an empty array should be returned. An example of a sliced array that would fail:
// Sliced
array:6 [
0 => "like"
1 => "cats"
2 => "they're"
3 => "cut3"
4 => "and"
5 => "cuddly"
]
Any recommendations, got speed in mind...
From what I understood, you want to get the index from the $original array based on values in $slice, you can use the array_flip() and the array_unique() functions:
function array_keys_from_consec_values($original, $slice){
// Get rid of duplicates and flip the keys with the values
$index = array_unique($original);
$index = array_flip($index);
$result = [];
// Loop through the slice
foreach($slice as $key => $value){
// Check if the value exists in the indexed array
if(!isset($index[$value])){
// Return an empty array
return array();
}
// And get the key from the flipped array
$result[$key] = $index[$value];
}
return $result;
}
var_dump(array_keys_from_consec_values($original, $slice));
This will give:
array (size=6)
0 => int 2
1 => int 3
2 => int 4
3 => int 5
4 => int 6
5 => int 7
This works on your example data and may be good enough:
$r = array_keys(array_unique(array_intersect($o, $s)));
If not, since you have a slice:
if(($k = array_search($s[0], $o)) === false ||
array_values($r = array_slice($o, $k, count($s), true)) != $s) {
$r = [];
}
Find the first key of the original from the first value of the slice
Slice from the original (preserving keys) and compare to the slice
For your example this yields:
Array
(
[2] => like
[3] => cats
[4] => they're
[5] => cute
[6] => and
[7] => cuddly
)
I see after the fact that you want to get the keys:
$r = array_values(array_flip($r));
If the slice is an actual array_slice from the original then pass true as the forth parameter to preserve the keys.
Good effort people, I admit the request was slightly hard to explain - so didn't get exactly what I was looking for. I realised that what I wanted was essentially an array_search that returns multiple keys when the needles are found consecutively. I've gone ahead and made the function myself:
/**
* Search for consecutive needles in haystack and return the corresponding keys.
*
* #param array $needles => Array values.
* #param array $haystack => Array to search.
* #param int $searchDirection => [0] (forwards) | [1] (backwards).
* #return array
*/
function array_search_all_consec(array $needles, array $haystack, $searchDirection = 0)
{
$needlesInScope = array_values($needles); // Keys not relevant, reset them.
$haystackInScope = $haystack;
if (in_array(reset($needlesInScope), $keys = array_keys($haystackInScope))) {
$needlesLength = count($needlesInScope);
foreach (($searchDirection == 0 ? $keys : array_reverse($keys)) as $offset) {
$length = $offset + $needlesLength;
$sliced = array_slice($haystackInScope, $offset, $length);
if (empty(array_diff_assoc($needlesInScope, $sliced))) {
return range($offset, $length - 1);
}
}
}
return [];
}
Test 1
$o = [
0 => "hello",
1 => "i",
2 => "like",
3 => "cats",
4 => "they",
5 => "cute",
6 => "and",
7 => "cuddly",
8 => "you",
9 => "know",
10 => "well",
11 => "i",
12 => "love",
13 => "cats",
];
$s = [
"i",
"love",
"cats",
];
return array_search_all_consec($s, $o);
// Result
array(3) {
[0] =>
int(11)
[1] =>
int(12)
[2] =>
int(13)
}
Test 2
$s = [
"i",
"like",
"cats",
];
return array_search_all_consec($s, $o);
// Result
array(3) {
[0] =>
int(1)
[1] =>
int(2)
[2] =>
int(3)
}
Test 3
$s = [
"i",
"lov3",
"cats",
];
return array_search_all_consec($s, $o);
// Result
array(0) {
}
Test 4
$s = [
"cats",
"i",
"love",
];
return array_search_all_consec($s, $o);
// Result
array(0) {
}
Test 5
$s = [
"i",
"love",
"cats",
"blah",
];
return array_search_all_consec($s, $o);
// Result
array(0) {
}
So there you have it. If anyone can improve the efficiency of the function please do contribute!

Indent value from array in php like a table

I've an array like:
$array = array(
0 => "A",
1 => "B",
2 => "C",
3 => "D",
4 => "E",
5 => "F",
6 => "G",
7 => "H",
);
Max lenght $array can be is 9, so max is index = 8 and min is 0 (at least 1 element inside array).
I've to indent this list inside a TCPDF box with limited height where, with some test, i've seen can support max 3 lines. But this box is large so, when the array lenght is bigger than 3, the others element need to be aligned in the side of the first column created like:
A D G
B E H
C F
I can't use X,Y coordinated cause i'm using writeHTML method in TCPDF.
I need to create 3 strings like:
$line1 = "A D G";
$line2 = "B E H";
$line3 = "C F";
What's the best method to create this 3 variables from my array?
UPDATE: using suggest method array_chunk is not the solution for me cause for my purpose I'd like to receive an array like:
Array ( [0] => Array (
[0] => A
[1] => D
[2] => G
)
[1] => Array (
[0] => B
[1] => E
[2] => H
)
[2] => Array (
[0] => C
[1] => F )
)
I think a for loop can solve OP's problem. This is another possible solution that use PHP array functions:
<?php
$array = array(
0 => "A",
1 => "B",
2 => "C",
3 => "D",
4 => "E",
5 => "F",
6 => "G",
7 => "H",
);
$cols = 3;
$array = array_chunk($array, $cols);
$results = array_map(function($index) use ($array) {
return array_column($array, $index);
}, range(0, $cols - 1));
var_dump($results);
View online here: https://eval.in/945787
<?php
$array = array(
0 => "A",
1 => "B",
2 => "C",
3 => "D",
4 => "E",
5 => "F",
6 => "G",
7 => "H",
);
$array_chunk = array_chunk($array, 3,false);
$line = '';
foreach ($array_chunk as $chunk_key => $chunk_value) {
$line = '"';
foreach ($chunk_value as $key => $value) {
$line.=$value." ";
}
$line = "$" . "line" . ($chunk_key+1) . " = " . rtrim($line, " ") . '"' . "<br/>";
echo $line;
$line='';
}
Demo

Filtering a php array using binary

A have a php array
$arr = array(
1 => "a",
2 => "b",
4 => "c",
8 => "d",
16 => "e",
32 => "f"
);
and a binary number
$filter=101101
I want to filter the array and keep only the keys where the respective value on binary is 1
For this example I would have:
$arr = array(
1 => "a",
4 => "c",
8 => "d",
32 => "f"
);
Or for
$filter=110001
to get
$arr = array(
1 => "a",
2 => "b",
32 => "f"
);
Assuming that the length of $filter is always the same as the number of array elements:
$filter_arr = str_split($filter);
$new_arr = array();
$i = 0;
foreach ($arr as $key => $val) {
if ($filter_arr[$i] == 1) {
$new_arr[$key] = $val;
}
$i++;
}
Using your given array, and filter equal to 101101, $new_arr will equal:
Array
(
[1] => a
[4] => c
[8] => d
[32] => f
)
See demo
This should work for you:
<?php
$arr = array(
1 => "a",
2 => "b",
4 => "c",
8 => "d",
16 => "e",
32 => "f"
);
$filter=110001;
$filerValue = str_split($filter);
$count = 0;
foreach($arr as $k => $v) {
if($filerValue[$count] == 0)
unset($arr[$k]);
$count++;
}
var_dump($arr);
?>
Output:
array(3) {
[1]=>
string(1) "a"
[2]=>
string(1) "b"
[32]=>
string(1) "f"
}

PHP split array based on value duplicated [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Here is an example array I want to split:
(1,2,3,4,5,0,6,7,0,8,9,10,11,12,0)
How do I split it in 3 arrays like this?
(1,2,3,4,5,0) (6,7,0) (8,9,10,11,12,0)
Here's the solution. (Author said he wants to split at '0' instead of duplicate values)
function split_array_by_duplicate_values($a, $duplicate = 0)
{
$c = array_intersect($a, array($duplicate));
$r = array();
$i = 0;
foreach($c as $k => $v) {
$l = ++$k - $i;
$r[] = array_slice($a, $i, $l);
$i = $k;
}
return $r;
}
$a = array(1,2,3,4,5,0,6,7,0,8,9,10,11,12,0);
print_r(split_array_by_duplicate_values($a));
returns
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 0
)
[1] => Array
(
[0] => 6
[1] => 7
[2] => 0
)
[2] => Array
(
[0] => 8
[1] => 9
[2] => 10
[3] => 11
[4] => 12
[5] => 0
)
)
Try this:
$array = array(1, 2, 3, 0, 4, 5, 6);
$array_0 = array_splice($array, 0, 4);
$array_1 = array_splice($array, 4);
I think what you're looking for is array_splice.
$array=array(1,2,3,0,4,5,6);
$newarray=array_splice($array,4);
print_r($array); //Array ( [0] => 1 [1] => 2 [2] => 3 [3]=>0);
print_r($newarray); //Array( [0]=>4 [1]=>5 [2]=>6)
If you want to split an array into two arrays in one multidimensional array, you could do
$array=array(1,2,3,0,4,5,6);
$newarray=array_chunk($array,4); //returns [[1,2,3,0],[4,5,6]]
You should use array split to split the array as you would like
<?php
$input = array("a", "b", "c", "d", "e");
$output = array_slice($input, 2); // returns "c", "d", and "e"
$output = array_slice($input, -2, 1); // returns "d"
$output = array_slice($input, 0, 3); // returns "a", "b", and "c"
// note the differences in the array keys
print_r(array_slice($input, 2, -1));
print_r(array_slice($input, 2, -1, true));
?>

I want to sort an array in reverse order of values in php

I want to sort an array in reverse order of values. I used arsort php function but the result is not good for me.
Example:
I want to sort next array:
myArray = array("d" => 1, "f" => 2, "b" => 3, "c" => 4, "e" => 2);
after using arsort php function the result is:
myArray =array ( "c" => 4, "b" => 3, "e" => 2, "f" => 2, "d" => 1 );
which it is not good because the arsort function doesn't keep initial order of elements in array.
I want the result like:
myArray =array ( "c" => 4, "b" => 3, "f" => 2, "e" => 2, "d" => 1 );
f before e order, like from original array. keys with same value to not reverse.
Thanks.
Edit:
This isn't doable with a built in function and you need to implement your own sorting solution. You can follow this question I opened to understand more.
It is a coincidence that these solutions work:
$myArray = array("d" => 1, "f" => 2, "b" => 3, "c" => 4, "e" => 2);
uasort($myArray, function($a, $b){
if($a == $b)
return 1;
else
return $b - $a;
});
print_r($myArray);
or
$myArray = array("d" => 1, "f" => 2, "b" => 3, "c" => 4, "e" => 2);
uasort($myArray, function($a, $b){
return $a <= $b;
});
print_r($myArray);
This worked for me.
Since the asort and arsort functions seem to sort rows with equal values by descending key value, an arsort will "switch" a lower key value with a higher if the values are equal.
My solution was to sort low to high (asort), which still does the unwanted row flipping, and then reverse the array which moves the rows with identical values back into their correct respective positions.
orig: Array ( [0] => 1 [1] => 0.5 [2] => 2 [3] => 3 [4] => 0.5 )
sorted: Array ( [4] => 0.5 [1] => 0.5 [0] => 1 [2] => 2 [3] => 3 ) - notice the key values were flipped for the identical valued rows
reversed: Array ( [3] => 3 [2] => 2 [0] => 1 [1] => 0.5 [4] => 0.5 ) - now you have reverse sorted the array and kept key integrity for rows with equal values.
$array=array(1,.5,2,3,.5);
asort($array);
$array=array_reverse($array,TRUE);
Please try this
arsort($array, krsort($array));
I think that your best bet will be to use uasort php function.
The advantage of using uasort in your case it will be that you have the change to define your own sort algorithm and not be tie to php asort comparison method.
You must define a callback function to evaluate if the first value is less than, greater than or equal to the second value.
You must check the php official online documentation to understand what this function does but I think quite easy to grasp so I will leave my own solution to your problem.
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? 1 : -1;
}
With this callback function you do a reverse sort while keeping the original order of the keys when they have the same value.
Best,
Demian
An easy, anywhere applicable way is:
<?php $a = array_flip($a); ksort($a); $a = array_flip($a); ?>
Array_flip flips each key <==> value.
Sort the array by the "now-keys";
Array_flip again to get the former constellation and a by-value sorted array.
-- P.s.: --
Why being so complicated? #others.
It seems that no response is correct for the next array:
$myArray = array(
"d" => 1, "Mircea Anca" => 2,
"b" => 3, "Iuliana Moise" => 2,
"c" => 4, "Florina Popescu" => 2 )

Categories