Is there a fast way of doing something like this Compare two arrays with the same value but with a different order in PHP?
I have arrays with potentially same data but in different order and I just need to see whether they are identical.
OK, turns out I get back an object and not an array, I guess...
object(Doctrine\ORM\PersistentCollection)#560 (9) etc.
hmm... Would the easiest way perhaps to iterate over the contents of the collection in order to create my own array and then compare like you all suggested?
Just adding code for my final solution
//Find out if container receives mediasync
$toSync = array();
foreach($c->getVideosToSync() as $v) {
$toSync[] = $v->getId();
}
$inSync = array();
foreach($c->getVideosInSync() as $v) {
$inSync[] = $v->getId();
}
$noDiff = array_diff($toSync, $inSync);
$sameLength = count($toSync) === count($inSync);
if( empty($noDiff) && $sameLength ) {
$containerHelper[$c->getId()]['syncing'] = false;
}
else {
$containerHelper[$c->getId()]['syncing'] = true;
}
I solved it the following way:
<?php
$arrayOld=array(
'1'=>'32',
'2'=>'34',
'3'=>'36',
'4'=>'38',
'5'=>'40',
'6'=>'42',
'7'=>'44',
);
$arrayNew=array(
'2'=>'32',
'1'=>'34',
'3'=>'36',
'4'=>'38',
'5'=>'46',
'6'=>'42',
'7'=>'44',
);
/**
* Here we check if there is any difference in keys or values in two arrays
* array_intersect_assoc - returns values that are same in both arrays checking values as well as keys
* array_diff returns the difference between the arrayNew values and those same values in both arrays, returned by array_intersect_assoc
*/
$result = array_diff($arrayNew,array_intersect_assoc($arrayOld, $arrayNew));
print_r($result);
//result is:
Array (
[2] => 32,
[1] => 34,
[5] => 46,
)
/** We can see, that the indexes are different for values 32 and 34
* And the value for index 5 has also changed from 40 to 46
*/
Just get them in a uniform order using sort() & then diff with them with array_diff().
# Set the test data.
$array1 = array(1,2,3,4,9,10,11);
$array2 = array(3,4,2,6,7);
# Copy the arrays into new arrays for sorting/testing.
$array1_sort = $array1;
$array2_sort = $array2;
# Sort the arrays.
sort($array1_sort);
sort($array2_sort);
# Diff the sorted arrays.
$array_diff = array_diff($array1_sort, $array2_sort);
# Check if the arrays are the same length or not.
$length_diff = (count($array1) - count($array2));
$DIFFERENT_LENGTH = ($length_diff != 0) ? true : false;
# Check if the arrays are different.
$ARE_THEY_DIFFERENT = ($array_diff > 1) ? true : false;
if ($DIFFERENT_LENGTH) {
echo 'The are different in length: ' . $length_diff;
}
else {
echo 'They have the same length.';
}
echo '<br />';
if ($ARE_THEY_DIFFERENT) {
echo 'They are different: ' . implode(', ', $array_diff);
}
else {
echo 'They are not different.';
}
echo '<br />';
Related
I have the following array:
$array = [2,2,5,2,2];
I would like to get the number which is different from the others, for example all the numbers are 2 except the number 5. So Is there anyway to get the different number using any array method or better solution? My solution is:
$array = [2,2,5,2,2];
$array1 = [4,4,4,6,4,4,4];
$element = -1;
$n = -1;
$count = 0;
for($i=0; $i<count($array1); $i++) {
if($element !== $array1[$i] && $element !== -1 & $count==0) {
$n = $array1[$i];
$count++;
}
$element = $array1[$i];
}
dd($n);
You can use array_count_values for group and count same value like:
$array = [2,2,5,2,2];
$countarray = array_count_values($array);
arsort($countarray);
$result = array_keys($countarray)[1]; // 5
Since you only have two numbers, you will always have the number with the least equal values in second position
Reference:
array_count_values
array_keys
A small clarification, for safety it is better to use arsort to set the value in second position because if the smallest number is in first position it will appear as the first value in the array
Sorting Arrays
You can user array_count_values which returns array with item frequency.
Then use array_filter to filter out data as follow:
$arrayData = [2,2,2,5];
$filterData = array_filter(array_count_values($arrayData), function ($value) {
return $value == 1;
});
print_r($filterData);
Inside array_filter(), return $value == 1 means only get the data with 1 frequency and thus filter out the other data.
<?php
function UniqueAndDuplicat($array){
$counts = array_count_values($array);
foreach ($counts as $number => $count) {
print $number . ' | ' . ($count > 1 ? 'Duplicate value ' : 'Unique value ') . "\n";
}
}
$array1 = [2,2,5,2,2];
$array2 = [4,4,4,6,4,4,4];
UniqueAndDuplicat($array1);
//output: 2 | duplicate value 5 | Unique value
UniqueAndDuplicat($array2);
//output: 4 | duplicate value 5 | Unique value
?>
Use this function to reuse this you just call this function and pass an Array to this function it will give both unique and duplicate numbers.
If you want to return only Unique number then use the below code:
<?php
function UniqueAndDuplicat($array){
$counts = array_count_values($array);
foreach ($counts as $number => $count) {
if($count == 1){
return $number;
}
}
}
$array1 = [2,2,5,2,2];
$array2 = [4,4,4,6,4,4,4];
echo UniqueAndDuplicat($array1); // 5
echo "<br>";
echo UniqueAndDuplicat($array2); // 6
?>
my task is to calculate average value from an array.
$arrayToTest = [[[1], 1], [[1,3,5,7], 4], [[2,5,4,1,2,3], 2.8],
[[-1,-1,-1,-1,-1], -1], [[4,23,84,12,76,34,-7,-23], 25.375]];
From inner array, so for example [1,3,5,7] and expected value is 4.
I have to use a function, I tried this:
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $case)
foreach ($case as $item)
{
$arraySum = array_sum($item);
$arrayCount = array_count_values($item);
$average = $arraySum / $arrayCount;
return $average;
}
}
but it does not work. I feel I'm doing something wrong with calling the inner array.
Comment:
I assume that you wish to calculate the average values of the innermost arrays.
The solution below returns the average of each array - not the average of all arrays. But - of course you easily could calculate the average of all arrays.
Therefore the function arrayAverage(…) returns an array of average values instead of the average value of (only) the last array.
I declared the input array (arrayToTest) explicitely, for the reason that one can better see the array structure (array of arrays and scalars) like this.
Code:
<?php
$arrayToTest = array (
array(
array(1),
1
),
array(
array(1,3,5,7),
4
),
array(
array(2,5,4,1,2,3),
2.8
),
array(
array(-1,-1,-1,-1,-1),
-1
),
array(
array(4,23,84,12,76,34,-7,-23),
25.375
)
);
echo '<pre>'; print_r($arrayToTest); echo '</pre>';
$average = arrayAvarage ($arrayToTest);
echo '<pre>'; print_r($average); echo '</pre>';
function arrayAvarage ($arrayToTest) {
$result = array();
foreach($arrayToTest as $case) {
foreach ($case as $items) {
if (!is_array($items)) continue;
$result[] = array_sum($items) / count($items);
}
}
return $result;
}
?>
Result:
Array
(
[0] => 1
[1] => 4
[2] => 2.8333333333333
[3] => -1
[4] => 25.375
)
if your array contains internal arrays in the index 0, you can do this by:
function arrayAvarage ($arrayToTest)
{
$out_put_arr = array();
foreach($arrayToTest as $case)
{
$arraySum = array_sum($case[0]);
$arrayCount = array_count_values($case[0]);
$avarage = $arraySum / $arrayCount;
$out_put_arr[]= $avarage;
}
return $out_put_arr;
}
so the loop for the main array, each item in the main array will give you array, and int $case[0] = [1,3,5,7] and $case[1] = 4, also you shouldn't return in for loop because this will return the first average only. so you can declare new array to fill with all averages.
function average($array){
return array_sum($array) / count($array);
}
foreach($arrayToTest as $array){
echo "Average: " . average($array[0]);
}
You should look at the first element of the $case array, which is the actual place where the array with values is situated. Note that you can also use the array_sum function.
Also, you should not return just like that, because that will interrupt the function from doing anything more. So, only return when you really want to do that.
As you already have expected values, I see no reason why your function should return those averages again. Instead it could verify the correctness of these expected values, and return the index of the array when that comparison fails.
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $index => $case) {
$average = array_sum($case[0]) / count($case[0]);
if ($average !== $case[1]) {
return $index; // not expected value
}
}
return false; // all averages are equal to expected value
}
So, the above function will return FALSE when all averages are as expected. Otherwise it will return the index of the first mismatch.
I have known the cause of the problem, not in the code.
Content of the field at the base value of each line separately
So used str_replace to delete the line
$query = $db->query_first("SELECT * FROM table ");
$array1 = explode(",",$query[filed1]);
$array1 = str_replace("\n","",$array1);
$array2 = explode(",",$query[filed2]);
$array2 = str_replace("\n","",$array2);
foreach($array1 as $value)
{
if (in_array($value,$array2))
{
//true
}else{
//false
}
}
I have a problem when I check if Each value in $array2 is present in $array1 or not
Table data:
filed1 | filed2
ahmed,jon,maya,omar | omar,maya
My code:
$query = $db->query_first("SELECT * FROM table ");
$array1 = explode(",",$query[filed1]);
$array2 = explode(",",$query[filed2]);
$length = count($array1);
for ($i = 0; $i < $length; $i++)
{
if (in_array($array1[$i] , $array2))
{
//true
}else{
//false
}
}
or this:
$query = $db->query_first("SELECT * FROM table ");
$array1 = explode(",",$query[filed1]);
$array2 = explode(",",$query[filed2]);
foreach($array1 as $value)
{
if (in_array($value,$array2))
{
//true
}else{
//false
}
}
My problem is my code doesn't work good, I am sure that my query gives the results and arrays too.
Output of array1:
Array ( [0] => maya [1] => omar [2] => ahmed [3] => join)
Output of array2:
Array ( [0] => omar [1] => maya )
So, where is the error in my code?!
Note :
I don't want check all value from array2 are in array1, I want check if Each value in $array2 is present in $array1 or not - focus on this word Each value not all value
Like:
if (in_array('omar',$array1))
{
echo 'found';
}else{
echo 'not found'; }
if (in_array('maya',$array1))
{
echo 'found';
}else{
echo 'not found';
}
if (in_array('jon',$array1))
{
echo 'found';
}else{
echo 'not found';
}
etc ...
But I do not want it this way, I want it inside a loop.
Yes you can use a loop in this case if you really want to, a simple foreach should suffice:
$array1 = array_map('trim', $array1); // on explode make sure remove trailing/leading spaces
$array2 = array_map('trim', $array2);
foreach($array1 as $name) { // so each value of array1
if(in_array($name, $array2)) { // is compared inside the contents of array2
// if found
echo "$name is found in " . '$array2';
} else {
echo "$name is NOT found in " . '$array2';
}
}
I think you should be iterating over array2 so all values of array2 are checked, not the other way around, because you said: "
check if Each value in $array2...
$query = $db->query_first("SELECT * FROM table ");
$array1 = explode(",",$query['filed1']);
$array2 = explode(",",$query['filed2']);
foreach($array2 as $value)
{
if (in_array($value,$array1))
{
//true
}else{
//false
}
}
I have known the cause of the problem, not in the code ...
Content of the field at the base value of each line separately
So used str_replace to delete the line
$query = $db->query_first("SELECT * FROM table ");
$array1 = explode(",",$query[filed1]);
$array1 = str_replace("\n","",$array1);
$array2 = explode(",",$query[filed2]);
$array2 = str_replace("\n","",$array2);
foreach($array1 as $value)
{
if (in_array($value,$array2))
{
//true
}else{
//false
}
}
array_diff() is a single function approach to getting an array of items not present in further arrays
$array1 = array('ahmed','jon','maya','omar');
$array2 = array('omar','maya');
$result = array_diff($array1,$array2); // Array ( [0] => ahmed [1] => jon )
you may need to switch parameter order to achieve your desired outcome.
you can also use array_intersect() to perform the reverse
#Ghost's solution produced the correct output, but as you state, you know the problem isn't your code. Apparently the problem is that the format of the data you are querying isn't quite matching. So, here is how you can approach debugging this problem:
var_dump() the data
The likely suspect is that some of the data have padding. (It's odd that #Ghost's suggestion of trimming the results didn't work.)
$array1 = explode(",",$query['filed1']);
$array2 = explode(",",$query['filed2']);
var_dump($array1);
echo "\n";
var_dump($array2);
echo "\n";
Inspect comparisons in the iteration
The above should reveal the problem. If not, you could take it a step deeper and see which exact comparison is failing in the in_array. If you don't have xdebug available, just loop within the loop:
foreach ($array1 as $value) {
if (in_array($value, $array2)) {
echo "\n[$value found in \$array2]\n";
} else {
echo "\n[$value NOT found in \$array2]\n";
}
foreach ($array2 as $value2) {
if ($value !== $value2) {
echo "\$array1's '$value' !== \$array2's '$value2'\n";
} else {
echo "\$array1's '$value' === \$array2's '$value2'\n";
}
}
}
The output will show you exactly what is wrong.
Note: You should include filed1 and filed2 in quotes since you are using them as string keys. When PHP parses your code, it will emit a notice (error) and fall back on interpreting it as a string.
I have a table that I need to find "top trusted builder" from, Trusts are separated by " ; ", So I need to pull all the data, explode the usernames, order and count them, and Im stuck on finally outputting the top username form the array, I have posted up the full segment of PHP, because im sure there has to be a much better way of doing this.
<?php
$GTB = $DBH->query('SELECT builders from griefprevention_claimdata where builders <> ""');
$GMCB->setFetchMode(PDO::FETCH_ASSOC);
$buildersarray = array();
while($row = $GTB->fetch()) {
$allbuilders = explode(";", $row['builders']);
for($i = 0; $i < count($allbuilders); $i++)
{
$buildersarray[] = $allbuilders[$i];
}
}
echo "<pre>";
print_r(array_count_values(array_filter($buildersarray)));
echo "</pre>";
?>
Outputs
Array
(
[username1] => 4
[username2] => 1
[username3] => 1
)
You can return the array from the array_count_values command into a new array called $topbuilders, and then echo out the current (first) record:
$topbuilders = array_count_values(array_filter($buildersarray));
echo current(array_keys($topbuilders)).', Rank = '.current($topbuilders);
current() will return the first item in an associative array.
Instead of using array_count_values() it would be better to use the names as the key to a frequency array:
$GTB = $DBH->query('SELECT builders from griefprevention_claimdata where builders <> ""');
$result = array();
while (($builders = $GTB->fetchColumn()) !== false) {
foreach (explode(";", $builders) as $builder) {
if (isset($result[$builder])) {
$result[$builder]++;
} else {
$result[$builder] = 1;
}
}
// sort descending based on numeric comparison
arsort($result, SORT_NUMERIC);
echo "Name = ", key($result), " Count = ", current($result), "\n";
i have multidimension array
$a = "5,add|4,edit|6,add|6,edit|19,add|19,delete|19,view";
then i explode $a
$array_a = explode("|", $a);
//loop
for($i=0;$i<=count($arr_a)-1;$i++){
arr_b = explode(",", $arr_a[$i]);
foreach($arr_b as $id => $access){
echo $id." have access ".$access;
}
}
//result
0 have access 5
1 have access add
0 have access 4
1 have access edit
0 have access 6
1 have access add
0 have access 6
1 have access edit
0 have access 19
1 have access add
0 have access 19
1 have access delete
0 have access 19
1 have access view
//-end result
the problem is :
how i can make the result like this
5 have access add
4 have access edit
6 have access add,edit
19 have access add,delete,view
I think Regex would be a better solution in this case, in case you haven't considered using it.
Sample (Tested):
$a = "5,add|4,edit|6,add|6,edit|19,add|19,delete|19,view";
$result = array();
// match each pair in the input
if (preg_match_all('/(\\d+)\\,(.*?)(\\||$)/m', $a, $matches)){
foreach( $matches[1] as $match_index => $match ){
$result[$match][] = $matches[2][$match_index];
}
}
// loop through the results and print in desired format
foreach( $result as $entry_index => $entry ){
echo "$entry_index have access " . implode( ',', $entry ) . "\n";
}
output:
5 have access add
4 have access edit
6 have access add,edit
19 have access add,delete,view
Using regex simplifies the code and also makes it somewhat easier to change the format of the input that is supported.
The $result array ended up with a hash map using your numeric ids as the keys and arrays of permissions (add, delete, etc) as the value for each key.
Try this one (tested):
// intial data
$strAccess = "5,add|4,edit|6,add|6,edit|19,add|19,delete|19,view";
// build access array
$arrayAccess = array();
$tmpList = explode('|', $strAccess);
foreach($tmpList as $access)
{
list($idUser, $right) = explode(',', $access);
if (!isset($arrayAccess[$idUser]))
$arrayAccess[$idUser] = array();
$arrayAccess[$idUser][] = $right;
}
// print it out
foreach($arrayAccess as $idUser => $accessList)
echo $idUser." has access ".implode(",", $accessList)."\n";
You can use counter something like
$count5=0;
foreach($arr_b as $id => $access){
if($access=='5'){
$count5++;
}
echo $id." have access ".$count5;
}
$a = "5,add|4,edit|6,add|6,edit|19,add|19,delete|19,view";
$array_a = explode("|". $a);
//loop
$aRights = array();
for($i=0;$i<=count($arr_a)-1;$i++){ $arr_b = explode(",", $arr_a[$i]);
foreach($arr_b as $id => $access){
$aRights[$id][] = $access;
}
}
foreach( $aRights as $id=>$rightsList){
echo $id." have access ";
$i=1;
foreach($rightsList as $r){
echo $r;
if($i != count($rightsList)) echo ",";
$i++;
}
}
What about something like hashmapping:
$tobegenerated = array();
$a = explode(yourdelimiter,yourstring);
foreach ($a as $cur)
{
$b = explode(delimiter,$cur);
$tobegenerated[$cur[0]] = $cur[1];
}
//Print hashmap $tobegenerated
This should work, remember that in php arrays are also hash maps
Edit 1:
Arrays in PHP are hash maps. A hash map can be interpreted as an array where keys can be anything and value can be anything too. In this case, you would like to use a hash map because you need to bind values that are "outside" the range of the array (even if they are ints). So a hash map is exactly what you want, allowing to specify anything as a key.
How a hash map work is something that you can search on google or on wikipedia. How arrays work in php can be found here