I'm trying to compare two 2D arrays in PHP and my head is hurting with all the recursion - this'll probably be obvious to someone who's used to it.
I have two 2D arrays which look like this, called $submittedArray2D and $dbArray:
{
[0] => {
[0] => 'name'
[1] => 'sectors'
[2] => 'address'
[3] => 'url'
}
[1] => {
[0] => 'name'
[1] => 'sectors'
[2] => 'address'
[3] => 'url'
}
...
}
$submittedArray2D comes from user input, while $dbArray holds what is already in the database.
I want to compare them to see if any of the values have been updated in $submittedArray2D, and save those changes to $dbArray accordingly.
I also want to pass any changed addresses to a separate function for geocoding, the results of which will be stored in another database field, where the keys reference the same entry in $dbArray (so $geocode[4] refers to $dbArray[4], for example).
I've tried out some foreach statements to go through the arrays sequentially, but this breaks down if one of the entries has been removed from the middle of the array, because the two arrays are no longer in sequence. I'm wondering whether some kind of ID for each array entry might make sense, but I'm not sure where to start.
Any ideas or pointers would be much appreciated!
I managed it in the end by storing a unique ID alongside each array element, that was it was possible to loop through and check whether that ID existed in the comparator array and then check whether the address had changed, and if so store the change (along with the ID) in a separate array for processing.
Related
I want to check, if array A contains all the items from array B (may contain others, but must contain all), when both arrays are multidimensional, i.e. can contains different variable types.
I've seen a lot (particularly this, this, this, this, this and this, also this, this and this as well). I've read PHP doc. Everything, that I checked, fails with "Array to string conversion" notice. Especially wen using array_intersect() or array_diff().
I'm using strict error checking, so notices actually holds further execution of entire script and are something, I don't generally like and want to avoid. Is it possible in this case?
My array A is:
Array
(
[0] => content/manage/index
[Content] => Array
(
[title] =>
[type] => 5
[category] =>
[recommended] =>
[featured] =>
[status] =>
[views] =>
[last_access_date] =>
[creation_date] =>
[modification_date] =>
[availability_date] =>
[author_id] =>
)
)
My array B is:
Array
(
[0] => /content/manage/index
[Content] => Array
(
[type] => 1
)
)
So, is there any way I can if I can use array_intersect on multidimensional arrays containing different variable types without getting notice?
My problem (and question) came out of misunderstanding, what "Array to string conversion" notice really means. In my case, it was trying to tell me, that I'm trying to walk multidimensional array with functions designed to be used on single dimension array.
Understanding that led me to a solution within few seconds. There are many of them here, on SO, but the one given by deceze here looked the best for me. So I adopted it into the form of such function:
function recursiveArrayIntersect($array1, $array2)
{
$array1 = array_intersect_key($array1, $array2);
foreach($array1 as $key=>&$value)
{
if(is_array($value)) $value = recursiveArrayIntersect($value, $array2[$key]);
}
return $array1;
}
I adopted it to my project and my way of coding, but all the credits still goes to deceze (his answer here)!
Now I can find an intersection of virtually any array, no matter what kind of variable types it contain and no matter of, how deep it is (how many subarrays it contains).
I have a very strange array sorting related problem in PHP that is driving me completely crazy. I have googled for hours, and still NOTHING indicates that other people have this problem, or that this should happen to begin with, so a solution to this mystery would be GREATLY appreciated!
To describe the problem/question in as few words as possible: When sorting an array based on values inside a multiple levels deeply nested array, using a foreach loop, the resulting array sort order reverts as soon as execution leaves the loop, even though it works fine inside the loop. Why is this, and how do I work around it?
Here is sample code for my problem, which should hopefully be a little more clear than the sentence above:
$top_level_array = array('key_1' => array('sub_array' => array('sub_sub_array_1' => array(1),
'sub_sub_array_2' => array(3),
'sub_sub_array_3' => array(2)
)
)
);
function mycmp($arr_1, $arr_2)
{
if ($arr_1[0] == $arr_2[0])
{
return 0;
}
return ($arr_1[0] < $arr_2[0]) ? -1 : 1;
}
foreach($top_level_array as $current_top_level_member)
{
//This loop will only have one iteration, but never mind that...
print("Inside loop before sort operation:\n\n");
print_r($current_top_level_member['sub_array']);
uasort($current_top_level_member['sub_array'], 'mycmp');
print("\nInside loop after sort operation:\n\n");
print_r($current_top_level_member['sub_array']);
}
print("\nOutside of loop (i.e. after all sort operations finished):\n\n");
print_r($top_level_array);
The output of this is as follows:
Inside loop before sort operation:
Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_2] => Array
(
[0] => 3
)
[sub_sub_array_3] => Array
(
[0] => 2
)
)
Inside loop after sort operation:
Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_3] => Array
(
[0] => 2
)
[sub_sub_array_2] => Array
(
[0] => 3
)
)
Outside of loop (i.e. after all sort operations finished):
Array
(
[key_1] => Array
(
[sub_array] => Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_2] => Array
(
[0] => 3
)
[sub_sub_array_3] => Array
(
[0] => 2
)
)
)
)
As you can see, the sort order is "wrong" (i.e. not ordered by the desired value in the innermost array) before the sort operation inside the loop (as expected), then is becomes "correct" after the sort operation inside the loop (as expected).
So far so good.
But THEN, once we're outside the loop again, all of a sudden the order has reverted to its original state, as if the sort loop didn't execute at all?!?
How come this happens, and how will I ever be able to sort this array in the desired way then?
I was under the impression that neither foreach loops nor the uasort() function operated on separate instances of the items in question (but rather on references, i.e. in place), but the result above seems to indicate otherwise? And if so, how will I ever be able to perform the desired sort operation?
(and WHY doesn't anyone else than me on the entire internet seem to have this problem?)
PS.
Never mind the reason behind the design of the strange array to be sorted in this example, it is of course only a simplified PoC of a real problem in much more complex code.
Your problem is a misunderstanding of how PHP provides your "value" in the foreach construct.
foreach($top_level_array as $current_top_level_member)
The variable $current_top_level_member is a copy of the value in the array, not a reference to inside the $top_level_array. Therefore all your work happens on the copy and is discarded after the loop completes. (Actually it is in the $current_top_level_member variable, but $top_level_array never sees the changes.)
You want a reference instead:
foreach($top_level_array as $key => $value)
{
$current_top_level_member =& $top_level_array[$key];
EDIT:
You can also use the foreach by reference notation (hat tip to air4x) to avoid the extra assignment. Note that if you are working with an array of Objects, they are already passed by reference.
foreach($top_level_array as &$current_top_level_member)
To answer you question as to why PHP defaults to a copy instead of a reference, it's simply because of the rules of the language. Scalar values and arrays are assigned by value, unless the & prefix is used, and objects are always assigned by reference (as of PHP 5). And that is likely due to a general consensus that it's generally better to work with copies of everything expect objects. BUT--it is not slow like you might expect. PHP uses a lazy copy called copy on write, where it is really a read-only reference. On the first write, the copy is made.
PHP uses a lazy-copy mechanism (also called copy-on-write) that does
not actually create a copy of a variable until it is modified.
Source: http://www.thedeveloperday.com/php-lazy-copy/
You can add & before $current_top_level_member and use it as reference to the variable in the original array. Then you would be making changes to the original array.
foreach ($top_level_array as &$current_top_level_member) {
I have an array with data, all with their own unique ID. I'm using the ORM method find('all') and the resulting array looks somewhat like this:
Array
(
[0] => Array
(
[Wijken] => Array
(
[id] => 1
[name] => Naam
[lat] => 13.37
[lon] => 13.37
[zoom] => 14
)
)
)
From my Routing I'm receiving an unique ID..
What I want, is re-use my array and get the data from, let's say, ID 1.
So what I need is that the indexes of my associative array (returned by find('')) are being set with the id of the "Wijken"-object itself.
I explained everything, just in case people have a different approach. Querying the database again with the param ID is not acceptable though.
try Set::combine
To maintain find('all') structure (from icc97 comment):
$idsAsIndexes = Set::combine($wijkens, '{n}.Wijken.id', '{n}');
Alternatively you can also extract a single model:
$idsAsIndexes = Set::combine($wijkens, '{n}.Wijken.id', '{n}.Wijken');
hope that's what you are looking for :)
I don't know any way to have your id as a key in the array, and don't even think it is possible with Cake without doing something "funny".
But if you do a find all, I'd have to assume you are going to process the data and do a loop at some point, at which time you could have something like:
foreach ($wijkens as $wijken) {
[...]do the general things here[...]
if ($wijken['Wijken']['id'] == $url_id) {
[...]do the thing you want to specifically do to id = 1 here[...]
}
}
On the other hand, I understand you don't want any extra query, although it seems like a relative minor transaction cost to me, and is still what I would prefer.
I'm using cakephp and am getting back a "double array" where it is giving me 2 arrays where it should be 1, I have looked into the issue as far as cakephp and can't figure it out and just want to move past this for now so I am wondering if anyone knows how to unset a second array if a variable has 2 arrays.. below is the print_r of the array, its just one variable that has this, which I find odd.. so I want to make it so there is not a 2nd set of duplicate values, if I do an array_push it pushes both values for that index into the resulting new array index so that won't work
one variable is equal to the following:
Array ( [0] => 42 [1] => 62 ) Array ( [0] => 42 [1] => 62 )
EDIT:
This is not an issue of my printing out the array twice accidentally, as I said above, with a foreach array_push of the variable, i end up with this, which is odd:
Array ( [0] => 4242 [1] => 6262 )
EDIT:
This is the cakephp database call that I am using, I know I didn't ask this in regards to cakephp but since some people think this is impossible i am posting this just so you can see what it does if you want
$specificfields_array = $this->Mymodel->find('list', array('fields' =>'Mymodel.id'),
'conditions' => array('emailgroup' => $categorynumber, 'sent' => '0');));
EDIT:
This is what a "foreach" array_push is:
$mynewarray = array();
foreach ($specificfields as $specificfields_current) {
array_push ($mynewarray, $specificfields_current);
}
A variable cannot "have two arrays". It can be one array that has two arrays nested. The scenario you describe is impossible (probably there are two print_r there or there is a < character hiding stuff – check the HTML source).
Can you post the controller, the model and the view file with your print_r calls to the http://bin.cakephp.org/ site and post the links back here so we can see all of your code?
I want to change the format of this array to match another one. One was pulled from a database, and the other was made using space delimted user input and then explode();
So here are the arrays I want to change, this is from the database (mysql_fetch_array). It grabs the single field from all rows.
Array
(
[name] => daniel
)
Array
(
[name] => alex
)
Array
(
[name] => richard
)
And here is what I want it to look like. This was the output of the user submitted values, space delimted and using PHPs explode() function.
Array
(
[0] => daniel
[1] => alex
[2] => david
)
What I want to be able to do is have these in the same format so that I can compare the two. The end goal is to be able to compare the two arrays (user input and database results), and create a final array containing only values that the user has inputted that the database doesn't already contain.
So using the data above this would be my final array:
Array
(
[0] => david
)
I would really appreciate help with the first bit, and if anyone else has a better way to achieve the end goal that would be a great extra bonus! (I get the feeling it might be easier to do this with SQL queries but I'm really confusing myself with these arrays)
Thanks!
array_diff($user_array, $database_array);
You can construct the $database_array like this:
$database_array = array();
//assuming each db record has only one value
//while there are still results in the db, do:
$database_array[] = reset($fetched_record);
See array_diff.