Compare all values in php array with the other values - php

I have a php array
How can I compare all values of this array and filter out values based on custom logic (callback function maybe).
Essentially, I want to compare each array value with every other value within the array and based on some custom logic, either keep the value or remove it from the array
Thanks

Probably you have to do it manually:
function your_callback($a, $b)
{
return $a != $b;
}
$array = array(/** Your array here... **/);
$n = count($array);
$filtered = array();
for($i = 0; $i < $n; $i++)
{
$ok = true;
for($j = 0; $j < $n; $j++)
{
if($j != $i && !your_callback($array[$i], $array[$j])
{
$ok = false;
break;
}
}
if($ok)
array_push($filtered, $array[$i]);
}
unset($array);
$array = $filtered;
This example will filter unique values of array for example; change your_callback definition to implement other logic.

You can call array_map, passing your callback as the first argument, and passing your array twice, as the second and the third argument. In the callback function, you loop through the "second" array and return the element if you want.

If you are looking to compare values of one array with values of another array in sequence then my code is really simple: check this out it will work like this:
if (1st value of array-1 is equal to 1st value of array-2) { $res=$res+5}
if($_POST){
$res=0;
$r=$_POST['Radio1']; //array-1
$anr=$_POST['answer']; //array-2
$arr=count($r);
for($ac=0; $ac<$arr; $ac++){
if($r[$ac]==$anr[$ac]){
$res=$res+5;
}
}
echo $res;
}

Related

Right rotation on array in php

I have an array for example
$a = [1,2,3,4,5];
From this $a, how to take last one and set it first like [5,1,2,3,4]
And how do I take last two arrays to make it like [4,5,1,2,3]
You can combine using array_pop(), which pops the last element of the array out, and array_unshift() to push it to the front of the array. You can create a simple function for this,
function array_pop_unshift($array) {
array_unshift($array, array_pop($array));
return $array;
}
Then use it as
$a = [1,2,3,4,5];
$new = array_pop_unshift($a);
print_r($new); // [5,1,2,3,4]
To continue shifting it, just call the function again until you're done, for instance through a for loop,
$a = [1,2,3,4,5];
for ($i = 0; $i < 2; $i++) {
$new = array_pop_unshift($a);
}
print_r($new); // [4,5,1,2,3]
Live demo at https://3v4l.org/CoJZZ
If you want to avoid the cost of several array_unshift and array_pop, you can build a generator that plays with the array internal pointer.
If you really need a result array, use iterator_to_array() to create it:
$a = range(1,5);
function rotate(&$array, $step = 1) {
$length = count($array);
end($array);
while ($step--)
prev($array);
while ($length--) {
next($array);
if (key($array) === null)
reset($array);
yield current($array);
}
}
print_r(iterator_to_array(rotate($a, 2))); // [4,5,1,2,3]
demo
Note that the rotate() generator uses a reference to avoid the array copy but doesn't modify the orginal array: it only moves the array pointer n times (where n is the array length) from the choosen position. When the array pointer is out of the array (key() returns null) the array pointer is reseted. In other words it stays efficient even with a large array and many rotations (what I have called "step" in the code).
You are actually doing right rotation, not left. Anyway, here are functions for doing both of them. They are probably not the most efficient but they are short in code and pretty self-explanatory:
<?php
function rotateLeft($array, $times) {
for($i=0; $i<$times; $i++){
$array[] = array_shift($array);
}
return $array;
}
function rotateRight($array, $times) {
for($i=0; $i<$times; $i++){
array_unshift($array, array_pop($array));
}
return $array;
}
$a = [1,2,3,4,5];
$a = rotateRight($a, 1);
print_r($a);
?>
to take last one and set it first This is known as right rotation.
And
$k is the number of units the shifting should be. $a is the array.
for($x=0; $x < $k; $x++){
//remove last element
$last = array_pop($a);
//push last element to the beginning
array_unshift($a, $last);
}
array_pop() pops and returns the value of the last element of array, shortening the array by one element.
https://www.php.net/manual/en/function.array-pop.php
array_unshift() prepends passed elements to the front of the array
https://www.php.net/manual/en/function.array-unshift.php
You could create a function that takes two arguments $k(number of rotations), $a (the array) and returns the array after performing right rotation $k times.
function rotateRight($a, $k){
for($x=0; $x < $k; $x++){
//remove last element
$last = array_pop($a);
//push last element to the beginning
array_unshift($a, $last);
}
return $a;
}
And then call it accordingly.
Example:
$a = [1,2,3,4,5];
$a_one_shift = rotateRight($a, 1);
// [5,1,2,3,4];
$a_two_shift = rotateRight($a_one_shift, 1);
// [4,5,1,2,3];
Or you could pass 2 to directly get the array after two right rotations.
$a_new = rotateRight($a, 2);
// [4,5,1,2,3];
Rather than making iterated calls of array_pop() and array_unshift(), use an efficient, elegant approach that makes fewer function calls and has the lowest possible time complexity. Using early returns prevents making needless function calls for the same result.
Code: (Demo)
function popUnshift(array $indexedArray, int $popShiftsCount): array
{
$count = count($indexedArray);
if ($count < 2) {
return $indexedArray; // array cannot be rotated
}
$remainder = $popShiftsCount % $count;
if (!$remainder) {
return $indexedArray; // sought rotation is the original order
}
return array_merge(
array_splice($indexedArray, -$remainder),
$indexedArray
);
}
Disclosure: This answer was built on the CodeReview page (Codility cyclic rotation solution in PHP) where I offered this snippet in my review.
//$A input array, $K rotation times
function solution($A, $K) {
$new = array();
for($j=1;$j<=$K;$j++)
{
if(count($new)>0)
$A = $new;
for($i=0;$i<count($A);$i++)
{
if($i==0)
$new[$i] = $A[count($A)-1];
else
$new[$i] = $A[$i-1];
}
}
return $new;}

Using unset() on an array, but it keeps the value

I'm trying to remove an object from an array if one of his properties is null or empty, this is the code.
The array has been sorted using this function:
function sortArray($c1, $c2)
{
return ($c1->propertyToCheck < $c2->propertyToCheck);
}
In case it changes anything.
$myArray = array();
...
// Add values to the array here
...
usort($myArray,"sortArray");
for($i = 0; $i < count($myArray ); $i++)
{
if(empty($myArray[$i]->propertyToCheck))
{
unset($myArray[$i]);
// var_dump($myArray[$i]) returns NULL
}
}
echo json_encode($myArray);
// Returns the entire array, even with the values that shouldn't be there.
The code is inside a function but the array is created inside said function.
I'm using echo json_encode($myArray) to send the value back in AJAX, but the array sent is the entire array with every object inside it.
The count($myArray) is the "problem".
Once the unset() is "reached" there is one element less in the array and therefore the next call to count($myArray) will return n-1 of the previous iteration -> your loop doesn't get to the end of the array.
You have at least three choices (in ascending order of my preference)
a)
$maxIdx = count($myArray);
for($i = 0; $i < $maxIdx; $i++) {
b)
foreach( $myArray as $key=>$obj ) {
if(empty($obj->propertyToCheck)) {
unset($myArray[$key]);
c)
$myArray = array_filter(
$myArray,
function($e) {
return !empty($e->propertyToCheck);
}
);
(...and many more)
see also: http://docs.php.net/array_filter

Return values of an array from behind (last element) php

say I have an array
$test_backwards=array("something1","something2","something3");
this is just a testing example and it's important to note that values will be added dinamically in my final array. so is it possible to dynamically return values from behind, namely starting from the last element?
something like this but backwards
for($i=0;$i<count($test_backwards);$i++) {
echo $test_backwards.'<br>';
}
Just start at the end and decrement your index:
for ($i = count($test_backwards) - 1; $i >= 0; $i--) {
echo $test_backwards[$i].'<br>';
}
or use array_reverse() (slower):
$test_backwards = array_reverse($test_backwards);
for ($i = 0; $i < count($test_backwards); $i++) {
echo $test_backwards[$i].'<br>';
}
You can also use array_pop(), if you do not need to keep this array. Or you can assign it to a temp array and then array_pop it, it will get and delete value from last.
$temp = $test_backwards;
while(($item = array_pop($temp)) !== NULL ) {
echo $item;
}

How to make array compact after unsetting an index of it?

There is an array :
$ret = array();
... query execution
$ret['cnt'] = $this->db->num_rows(); // total number of database records
$i = 0;
while ( $this->db->next_record() ) { // fetching database records
$ret[$i]["user_id"] = $this->db->f('user_id') ;
$ret[$i]["user_login"] = stripslashes($this->db->f('user_login'));
$i++;
}
Now I want to remove from this array the element whose "user_id" is equal to a particular value :
if ($ret['cnt'] > 0) {
for ($i=0; $i<$ret['cnt']; $i++) {
if ($ret[$i]['user_id'] == $_SESSION[CODE_USER]) {
unset($ret[$i]);
break;
}
}
}
After printing the array I noticed that the element 0 is not in the array , this is what I am expecting. The only problem is now how to rearrange the array elements so that it will be compact again without any hole in its elements because the element 0 is not present ?
Use array_values:
$ret = array_values($ret);
http://php.net/manual/en/function.array-values.php
Or instead of using the 0th index. You could just grab the first element with reset.
http://php.net/manual/en/function.reset.php
array_values is probably the simplest way to reset keys.
if ($ret['cnt'] > 0) {
for ($i=0; $i<$ret['cnt']; $i++) {
if ($ret[$i]['user_id'] == $_SESSION[CODE_USER]) {
$ret = array_slice($ret,$i,1);
break;
}
}
}
array_slice will also strip away a section of the array and re-index as necessary.

How to sort it better?

I have 2 arrays, both are multidimensional with same number of elements and same values, which are on different positions (those values are actually ID-s from my database, so one ID appears only once). How can I sort second array with values which are in first array?
For example - if first array looks like:
$array1[0][0] = 1;
$array1[0][x] = it doesn't matter what's here
$array1[1][0] = 4;
$array1[1][x] = it doesn't matter what's here
$array1[2][0] = 3;
$array1[2][x] = it doesn't matter what's here
...
how to sort second array so it would have same values as array1 on indexes [0][0], [1][0], [2][0], etc.
How I could solve problem is:
$i=0
while ($i < (count($array1)-2)){ // * check down
$find_id = $array1[$i][0];
// here I need to search for index of that ID in other array
$position = give_index($find_id, $array2);
// swapping positions
$temp = array2[$i][0];
$array2[$i][0] = $array2[$position][0];
$array2[$position][0] = $temp;
// increasing counter
i++;
}
function give_index($needle, $haystack){
for ($j = 0, $l = count($haystack); $j < $l; ++$j) {
if (in_array($needle, $haystack[$j][0])) return $j;
}
return false;
}
*There is only -2 because indexes start from 0 and also for the last element you don't need to check since it would be automatically sorted by last iteration of while-loop.
I don't find this solution good as I think that this is quite simple issue (maybe it's not even correct). Is there easier way in PHP that I'm missing?
This is the most efficient way I can think of:
function swap(&$a, &$b) {
$t = $a;
$a = $b;
$b = $t;
}
function find_index($id, $array, $from = 0) {
$index = false;
for ($i = $from, $c = count($array); $i < $c; $i++) {
if ($array[$i][0] == $id) {
$index = $i;
break;
}
}
return $index;
}
for ($i = 0, $c = count($array1); $i < ($c - 2); $i++) {
if ($array1[$i][0] != $array2[$i][0]) {
$fi = find_index($array1[$i][0], $array2, $i);
swap($array2[$i][0], $array2[$fi][0]);
}
}
What changes from yours?
I've defined a swap() function in order to swap any variable. That doesn't cost anything and makes everything look nicer. Also you can reuse that function later if you need to.
In the find_index (give_index in your code) we stop the loop once we find the correct index. Also we avoid the cost of an in_array function call.
We modified the find_index function to start only from the part of the array we haven't checked yet. Leading to a way more efficient way of scan the array.
In the for loop (a while loop was just wrong there) we stored the count of the array once, avoiding multiple calls.
Also we swap the $array2 values only if they are in the wrong place.
Other improvements
If you know anything else of the $array2 array you can make this even more performant. For example if you know that indexes are alternated like in $array1 you can change the main for loop from:
for ($i = 0, $c = count($array1); $i < ($c - 2); $i++) {
to
for ($i = 0, $c = count($array1); $i < ($c - 2); $i+2) {
(notice the $i+2 at the end) And you could do that in the find_index function as well.
Look into usort (http://php.net/manual/en/function.usort.php).
It provides a simple way to sort arrays using a user provided comparison function.

Categories