Compare differences in Multidimensional array - php

I have a rather ugly query, and the results from the query are then post-processed using php which turns each row into it's own multidimensional array.
I want to refactor the query but need to make sure I do not change what it returns in any way.
So What I want to do is copy the original query and call that, store the results.
then run the function again with my new query.
Loop over the two arrays of results and compare them for any differences what so ever (keys, values, missing entries, type differences etc).
What is the easiest way to do this?
Essentially I know how to call the two queries etc,
I guess my real question is, at the end once I have my two arrays of the results how do I go through and compare them.
What I would love to end up with is a side by side "print_r" type output with a red line or similar going across highlighting any differences.

First of all, you can use array_uintersect_assoc() like this.
// First get intersecting values
$intersect = array_uintersect_assoc($expected, $results, "checkStructure");
print_r($intersect);
//Then print results that are in intersecting set (e.g. structure of $expected, value of $results
print_r(array_uintersect_assoc($results, $intersect, "checkStructure"));
function checkStructure($x, $y) {
if (!is_array($x) && !is_array($y)) {
return 0;
}
if (is_array($x) && is_array($y)) {
if (count($x) == count($y)) {
foreach ($x as $key => $value) {
if(array_key_exists($key,$y)) {
$x = checkStructure($value, $y[$key]);
if ($x != 0) return -1;
} else {
return -1;
}
}
}
} else {
return -1;
}
return 0;
}
If still not, take help of array_diff()
and array_diff_assoc(). Or try following code.
function multidimensional_array_diff($a1,$a2)
{
$r = array();
foreach ($a2 as $key => $second)
{
foreach ($a1 as $key => $first)
{
if (isset($a2[$key]))
{
foreach ($first as $first_value)
{
foreach ($second as $second_value)
{
if ($first_value == $second_value)
{
$true = true;
break;
}
}
if (!isset($true))
{
$r[$key][] = $first_value;
}
unset($true);
}
}
else
{
$r[$key] = $first;
}
}
}
return $r;
}

Why don't you just make a VIEW that turns an ugly query into something you can just SELECT against? What you're talking about is making a materialized view, something that MySQL doesn't handle as well as other database platforms.

Why not write the results of each query out to a text files then compare the two text files with the diff command?

Related

How to replace huge array with PHP generators

Seeking your help to convert one big array with PHP generators.
Below is my code for which I need rework:
I am getting a result set from a service call and assigning all to an array:
foreach ($objects->result as $pointStdObject) {
$pointStdObjects[] = $pointStdObject;
}
This piece of code is inside a while loop which queries for records with an offset of 1000.
Issue is $pointStdObjects[] tends to get very huge and I get PHP out of memory exception.
Later I again need to use this same array as:
foreach ($pointStdObjects as $pointStdObject) {
$point = $this->pointFactory->createPointFromStdObject($pointStdObject);
if (!$point) {
continue;
}
$points[] = $point;
}
return $points;
Please suggest if we can leverage PHP generators or yield here
function getStd()
{
///your code before that
foreach ($objects->result as $pointStdObject) {
yield $pointStdObject;
}
}
function useStd()
{
foreach (getStd() as $pointStdObject) {
$point = $this->pointFactory->createPointFromStdObject($pointStdObject);
if (!$point) {
continue;
}
$points[] = $point;
}
return $points;
}

How to know if an associative array has the same value for all the recurrence?

I have an associative array like this:
9584=>string
5324=>string
6543=>string
The key is always a number but I assign it dynamically so I don't know the numbers and probably they are not consecutive.
I need to know if the string is the same in ALL of the occurrence in the array.
If you can help me thank you... and sorry for my horrible English
Let me count the ways... There are bound to be more:
if(count(array_flip($array)) === 1) { }
if(count(array_unique($array)) === 1) { }
if(count(array_count_values($array)) === 1) { }
Read the first value and browse your array until you find a different one.
<?php
function allTheSame($array)
{
if (count($array) != 0)
{
$first = reset($array);
foreach($array => $v)
{
if ($v !== $first)
{
return false;
}
}
}
return true;
}

If true use foreach loop, else use while

I'm trying to link the MySQL while loop into foreach loop using something like this :
if($something == true){
foreach($array as $arr){
} else {
while($row = mysql_fetch_array($mysql_query)){
}
// loop instructions
}
It looks so wrong, I know but you see what I am trying to do ?.. I want to grab data from array if $something was true, else then grab data from database
I had another solution idea and its to manually match the array with how $mysql_query works so I can use them both with while only, something like this :
if($something == true){
$mysql_query = array("username" => "$_GET['username']", "password" => "$_GET['password']");
} else {
$mysql_query = mysql_query("SELECT * FROM users WHERE usern......");
}
while($row = mysql_fetch_array($mysql_query)){
...
That's a second way to do it but it looks wrong as well because the first array is normal, I want to match that normal array with how mysql_query builds it so it can fit with the while loop
P.S. : I DO NOT want to repeat writing the loop instructions, I want them both to work with only one like I mentioned above
Put your processing into a function:
function process_data($data) {
// do stuff
}
if($something){
foreach($array as $arr){
process_data($arr);
}
} else {
while($row = mysql_fetch_array($mysql_query)){
process_data($row);
}
}
The other answers here are fine, but you'd be better served just to make sure that $array is a valid array regardless of something ... How about
if (!something){
$array = array();
while($row=mysql_fetch_array($mysql_query)) {$array[] = $row;}
}
foreach($array as $arr){
// do work
}
You'd probably get a better answer if you expanded the scope of what you've explained a bit. Without knowing what the something is and what the data is, plus the ultimate objective then it's hard to tell what kind of structure you should be using.
It seems to me that you could achieve this by just using a function, if the code inside the loop is the same. Like this:
if($something == true)
{
foreach($array as $arr)
{
doWork($arr);
}
}
else
{
while($row = mysql_fetch_array($mysql_query))
{
doWork($row);
}
}
function doWork($arr)
{
//...
}
You cannot nest loop instructions inside a loop like this. You'll need to have two separate loops completely inside the IF statements.
if($something == true){
foreach($array as $arr){
// do work
}
} else {
while($row = mysql_fetch_array($mysql_query)){
// do work
}
}
Maybe you could look at from this viewpoint. And take note that this code uses mysql_fetch_assoc() instead of mysql_fetch_array(). Try both functions and look at the resulting rows with var_dump(). You will see that mysql_fetch_array() has twice as much data. You may want that, but probably not.
if ($something !== true)
{
$array = array();
while($row = mysql_fetch_assoc($mysql_query_result_resource))
{
$array[] = $row;
}
}
foreach($array as $arr)
{
/* PROCESS */
}

iterate through array, number of keys is variable, the first value being processed differently

Hi I have a PHP array with a variable number of keys (keys are 0,1,2,3,4.. etc)
I want to process the first value differently, and then the rest of the values the same.
What's the best way to do this?
$first = array_shift($array);
// do something with $first
foreach ($array as $key => $value) {
// do something with $key and $value
}
I would do this:
$firstDone = FALSE;
foreach ($array as $value) {
if (!$firstDone) {
// Process first value here
$firstDone = TRUE;
} else {
// Process other values here
}
}
...but whether that is the best way is debatable. I would use foreach over any other method, because then it does not matter what the keys are.
Here is one way:
$first = true;
foreach($array as $key => $value) {
if ($first) {
// something different
$first = false;
}
else {
// regular logic
}
}
$i = 0;
foreach($ur_array as $key => $val) {
if($i == 0) {
//first index
}
else {
//do something else
}
$i++;
}
I would do it like this if you're sure the array contains at least one entry:
processFirst($myArray[0]);
for ($i=1; $i<count($myArray); $1++)
{
processRest($myArray[$i]);
}
Otherwise you'll need to test this before processing the first element
I've made you a function!
function arrayCallback(&$array) {
$callbacks = func_get_args(); // get all arguments
array_shift($callbacks); // remove first element, we only want the callbacks
$callbackindex = 0;
foreach($array as $value) {
// call callback
$callbacks[$callbackindex]($value);
// make sure it keeps using last callback in case the array is bigger than the amount of callbacks
if(count($callbacks) > $callbackindex + 1) {
$callbackindex++;
}
}
}
If you call this function, it accepts an array and infinite callback arguments. When the array is bigger than the amount of supplied functions, it stays at the last function.
You can simply call it like this:
arrayCallback($array, function($value) {
print 'callback one: ' . $value;
}, function($value) {
print 'callback two: ' . $value;
});
EDIT
If you wish to avoid using a function like this, feel free to pick any of the other correct answers. It's just what you prefer really. If you're repeatedly are planning to loop through one or multiple arrays with different callbacks I suggest to use a function to re-use code. (I'm an optimisation freak)

break; vs continue; vs return;

I downloaded a free newsletter written in php from hotscripts.com
I updated a little the code to add new functionality and I saw something I don't understand.
In the code I see:
foreach() { ...
if() ...
break;
elseif() ...
continue;
}
I also saw:
function() {
// ...
for($nl = 0; ...
if() ...
return true;
}
I read that break; will stop the loop, continue will skip the loop to the next iteration and return will exit the function.
What I don't understand is why coding that style? Why not use something like:
function() {
// ...
for($nl = 0; ...
if() ...
$returnValue = true;
else {
$returnValue = false;
}
}
return $returnValue;
}
or same idea in the for loops?
Using keywords such as break and continue can make the code far easier to read than what you propose.
Especially if you are nesting if/else-statements more than one level.
Compare the snippets further down in this post, which one is easier to read?
Both of them output the same exact thing, and $A is array (1,2,4,4,3,4).
A return in a loop (inside a function) can save precious CPU cycles, if you know you don't need to loop any further, why do it?
I'm too cool to use break/continue..
$not_even_found = false;
foreach ($A as $v) {
if ($v != 1) {
if ($not_even_found) {
} else if ($v % 2 != 0) {
$not_even_found = true;
} else {
echo "$v\n";
}
}
}
I want to have readable code..
foreach ($A as $v) {
if ($v == 1)
continue;
if ($v % 2 != 0)
break;
echo "$v\n";
}
You code using that style so that you save unnecessary loops when the first time a condition is met then you already now that something is true and you don't need to investigate further.
In fact if you return you stop the loop. A stupid example
function in_array($needle, $haystack){
for($i = 0; $i < count($haystack); i++){
if($needle === $haystack[$i]{
return $i;
}
}
return -1;
}
in this case when the condition is met you return something (true, or in this case the value of the counter) because you don't need to iterato over the whole array
Some of the "why" comes down to personal preference. Some of it comes down to whether other things need to be done in the same function before it returns. If there's nothing else that needs to be done, and the function is simply supposed to return a true or false answer, then directly using return true; is the most expedient mechanism. If you still need to do some other stuff even after deciding whether to return true or not (close a file handle for example), then assigning the response to a variable and then returning that at the end may be necessary.

Categories