In PHP 5.5.33, I want to create an array of arrays, inside a repeat loop. I have found 3 different ways of doing this, which give 3 different results. The first result is the one I want, so I have a solution. What I need is an understanding of why these three ways lead to different outcomes.
The first two examples make sense to me. The third seems to apply alien logic. In the third example, I create a new reference to a new array on each iteration, and yet the same reference is added to the output array each time. Why does $inner, in the last example, not get recreated at a new memory address each time?
<?php
// Inner array added after it is changed
$outer = array();
for ($ii=0; $ii<3; $ii++) {
$inner = array("value" => 0);
$inner["value"] = $ii;
$outer[$ii] = $inner;
}
echo json_encode($outer);
// [{"value":0},{"value":1},{"value":2}]
?>
<br />
<?php
// Innner array added as a copy, and then changed
$outer = array();
for ($ii=0; $ii<3; $ii++) {
$inner = array("value" => 0);
$outer[$ii] = $inner;
$inner["value"] = $ii;
}
echo json_encode($outer);
// [{"value":0},{"value":0},{"value":0}]
?>
<br />
<?php
// Inner array created, then added by reference, then changed
$outer = array();
for ($ii=0; $ii<3; $ii++) {
$inner = array("value" => 0); // shouldn't this be different each time?
$outer[$ii] = &$inner;
$inner["value"] = $ii;
}
echo json_encode($outer);
// [{"value":2},{"value":2},{"value":2}]
?>
It is simple - on the 3th sample you're creating the array of 3 synonyms to the variable $inner['value']. In same tame you every time change the $inner['value'] to $ii. On the end you have array of 3 pointers, which point to $inner['value'], but $inner['value'] obtained 2 - that is and the result.
And in case you are expecting that $inner = array("value" => 0); will take different place - you aren't on right way. This is equal if you empty and create the array - it is reseting the array every time.
Related
I am looking for a way to create new arrays in a loop. Not the values, but the array variables. So far, it looks like it's impossible or complicated, or maybe I just haven't found the right way to do it.
For example, I have a dynamic amount of values I need to append to arrays. Let's say it will be 200 000 values. I cannot assign all of these values to one array, for memory reasons on server, just skip this part.
I can assign a maximum amount of 50 000 values per one array. This means, I will need to create 4 arrays to fit all the values in different arrays. But next time, I will not know how many values I need to process.
Is there a way to generate a required amount of arrays based on fixed capacity of each array and an amount of values? Or an array must be declared manually and there is no workaround?
What I am trying to achieve is this:
$required_number_of_arrays = ceil(count($data)/50000);
for ($i = 1;$i <= $required_number_of_arrays;$i++) {
$new_array$i = array();
foreach ($data as $val) {
$new_array$i[] = $val;
}
}
// Created arrays: $new_array1, $new_array2, $new_array3
A possible way to do is to extend ArrayObject. You can build in limitation of how many values may be assigned, this means you need to build a class instead of $new_array$i = array();
However it might be better to look into generators, but Scuzzy beat me to that punchline.
The concept of generators is that with each yield, the previous reference is inaccessible unless you loop over it again. It will be in a way, overwritten unlike in arrays, where you can always traverse over previous indexes using $data[4].
This means you need to process the data directly. Storing the yielded data into a new array will negate its effects.
Fetching huge amounts of data is no issue with generators but one should know the concept of them before using them.
Based on your comments, it sounds like you don't need separate array variables. You can reuse the same one. When it gets to the max size, do your processing and reinitialize it:
$max_array_size = 50000;
$n = 1;
$new_array = [];
foreach ($data as $val) {
$new_array[] = $val;
if ($max_array_size == $n++) {
// process $new_array however you need to, then empty it
$new_array = [];
$n = 1;
}
}
if ($new_array) {
// process the remainder if the last bit is less than max size
}
You could create an array and use extract() to get variables from this array:
$required_number_of_arrays = ceil($data/50000);
$new_arrays = array();
for ($i = 1;$i <= $required_number_of_arrays;$i++) {
$new_arrays["new_array$i"] = $data;
}
extract($new_arrays);
print_r($new_array1);
print_r($new_array2);
//...
I think in your case you have to create an array that holds all your generated arrays insight.
so first declare a variable before the loop.
$global_array = [];
insight the loop you can generate the name and fill that array.
$global_array["new_array$i"] = $val;
After the loop you can work with that array. But i think in the end that won't fix your memory limit problem. If fill 5 array with 200k entries it should be the same as filling one array of 200k the amount of data is the same. So it's possible that you run in both ways over the memory limit. If you can't define the limit it could be a problem.
ini_set('memory_limit', '-1');
So you can only prevent that problem in processing your values directly without saving something in an array. For example if you run a db query and process the values directly and save only the result.
You can try something like this:
foreach ($data as $key => $val) {
$new_array$i[] = $val;
unset($data[$key]);
}
Then your value is stored in a new array and you delete the value of the original data array. After 50k you have to create a new one.
Easier way use array_chunk to split your array into parts.
https://secure.php.net/manual/en/function.array-chunk.php
There's non need for multiple variables. If you want to process your data in chunks, so that you don't fill up memory, reuse the same variable. The previous contents of the variable will be garbage collected when you reassign it.
$chunk_size = 50000;
$number_of_chunks = ceil($data_size/$chunk_size);
for ($i = 0; $i < $data_size; $i += $chunk_size) {
$new_array = array();
foreach ($j = $i * $chunk_size; $j < min($j + chunk_size, $data_size); $j++) {
$new_array[] = get_data_item($j);
}
}
$new_array[$i] serves the same purpose as your proposed $new_array$i.
You could do something like this:
$required_number_of_arrays = ceil(count($data)/50000);
for ($i = 1;$i <= $required_number_of_arrays;$i++) {
$array_name = "new_array_$i";
$$array_name = [];
foreach ($data as $val) {
${$array_name}[] = $val;
}
}
According to http://assemblysys.com/php-point-in-polygon-algorithm/ I can take a group of points that form a polygon and determine whether or not a point resides inside or outside the polygon. I have also created an KML file when is being utilized by JavaScript to determine which points are inside, however my end goal would to have each marker contain an extra data set inside of a MySQL table that will store this data for later use resulting in a quicker map load time.
Looking through the KML file, each Polygon has a set of coordinates that are separated by ",0.0" which means little because according to the above document I only need the set of lats and longs. In addition, the latitudes and longitudes are in different places. Below is an example of the cordinates:
-86.1459875,39.8622513,0.0 -86.1459875,39.8555639,0.0 -86.1398077,39.8556628,0.0 -86.1398077,39.862218399999996,0.0 -86.1459875,39.8622513,0.0
Instead I want the set to look like the following:
39.8622513 -86.1459875, 39.8555639 -86.1459875, 39.8556628 -86.1398077, 39.862218399999996 -86.1398077, 39.8622513 -86.1459875
Below is a sample of my code, however I am not sure if there is an easier way of manipulating the array using PHP without the use of multiple for loops or foreach loops.
$kml = 'document.xml';
//get the total number polygons
$numPoly = count( $kml->Document[0]->Folder);
$newArray = array();
$a = 1;
$explode;
$explode['coordinates'];
for( $i=0; $i <= $numPoly; $i++)
{
$numPlace = count( $kml->Document[0]->Folder[$i]->Placemark); //count the number of placemarks there are
for($z = 0; $z <= $numPlace; $z++)
{
$regionName = $kml->Document[0]->Folder[$i]->Placemark[$z]->name."</br>"; //grab each placemarks name
//get the cordinates inside of each placemark
$regionCords = $kml->Document[0]->Folder[$i]->Placemark[$z]->Polygon->outerBoundaryIs->LinearRing->coordinates;
//print_r($regionCords); print "<br/><br/>";
foreach($regionCords as $num2 => $region)
{
print $a;
$explodeCords = array_splice( explode('|', str_replace(',0.0',' |', $regionCords) ), 0, -1 ) ;
foreach ($explodeCords as $exploded)
{
$exploded = explode(',', $exploded);
$exploded1 = $exploded[0];
$exploded2 = $exploded[1];
$explodedString = $exploded2.$exploded1.",";
//echo $explodedString; echo "<br/><br/>";
}
}
$numCordinates = count($explodeCords['coordinates'] ); //returns the number of [lat,long] cords in each cordinate set
if ( !empty( $regionCords ) )
{
$a++;
}
}
}
Please let me know if I am on the right path or if there is another way you can easily switch these two numbers using mostly array functions with PHP.
A solution: after each foreach loop, it is best practice to remove the new array out of the loop, because if you are to add another foreach loop, unwanted effects may result such as appending a value to a new array in multiples.
After the values are removed from the foreach loop, you can always use a array_map to switch the coordinates. For a more completed example of this please see the following Github repo: https://github.com/jdmagic21/GMapParse
i need to make an array like this
$privateMsgIdArray = array("idlistener" => $idlistener, "maxMsgId" => $lastMsgId);
I need to replace the maxMsgId to the corresponding idlistener, and if the idlistener that i pass doesn't not exist to create a new entry inside the array.
I am a but confused on how i am going to extract the maxMsgId value corresponding to an idlistener.
In other words i need to pass new values of idlisteners only once, and replace maxMsgId each time that they are not equal to the corresponing idlistener.
If the idlistener field doesn't exist create it (push into array).
I pass old array into a session and new array in the current run.
After the run i i replace them.
I believe this sounds a bit confusing though.
e.g
We have an array like this already:
[15][200]
next call maxMsgId is 210
array should be
[15][210]
next call we have a new listener id with maxMsgId 30
array should be
[15][210]
[16][30]
You should be able to accomplish this with a quick loop:
// your "new" values
$idListener = 15;
$maxMsgId = 210;
// loop over the array to see if it contains the `idlistener` you want
$end = count($privateMsgIdArray);
for ($i = 0; $i < $end; $i++) {
if ($privateMsgIdArray[$i]['idlistener'] == $idListener) {
// we found it! overwrite the `maxMsgId` field
$privateMsgIdArray[$i]['maxMsgId'] = $maxMsgId;
break;
}
}
if ($i == $end) {
// we reached the end of the array without finding the `$idListener`;
// add a new entry =]
$privateMsgIdArray[] = array(
'idlistener' => $idListener,
'maxMsgId' => $maxMsgId
);
}
This is a rather brute-force approach though and, if efficiency is something you're after, it would be wise to create a "cache"-style method of idlistener values and their index in the $privateMsgIdArray array.
For instance:
// key = idlistener, value = index in `$privateMsgIdArray`
$idCache = array(15 => 0, 16 => 1);
// check if the `$idListener` is in the cache
if (!isset($idCache[$idListener])) {
// it's not; add a new entry
$key = count($privateMsgIdArray);
$privateMsgIdArray[$key] = array(
'idlistener' => $idListener,
'maxMsgId' => $maxMsgId
);
// add the new index into the cache
$idCache[$idListener] = $key;
} else {
// it is in the cache; pull the corresponding index and set the `maxMsgId` =]
$privateMsgIdArray[$idCache[$idListener]]['maxMsgId'] = $maxMsgId;
}
Both of the approaches above could be converted into functions to make things "more portable" too.
I have an array with three indexes which themselves are arrays:
$array['title'];
$array['description'];
$array['link'];
I need to add to this array in a loop.
for ($i=0;$i<10;$i++)
{
// information is processed, different information on each loop
$array = $information['processed'];
}
The above works fine when I do it once without the loop, however I cannot add to $array.
What I have tried is:
$array = array();
$arraytemp = array();
for ($i=0;$i<10;$i++)
{
// information is processed, different information on each loop
$arraytemp = $information['processed'];
$array = $array + $arraytemp; // the unique append as outlined in php manual
}
I have also tried:
$array = array();
for ($i=0;$i<10;$i++)
{
// information is processed, different information on each loop
$array[] = $information['processed'];
}
And I have also tried:
$array = array();
for ($i=0;$i<10;$i++)
{
// information is processed, different information on each loop
array_push($array,$information['processed']);
}
For the application I am developing, I need a way of adding to this array whilst reserving the key structure. So I want to add the new information to the end of the array.
Creating a new dimension by doing something like the following is not appropriate for my program:
for ($i=0;$i<10;$i++)
{
// information is processed, different information on each loop
$array[$i] = $information['processed'];
}
//The above is not appropriate for my application
Any ideas?
Thanks guys.
$array = array();
for ($i=0;$i<10;$i++)
{
$array[$i] = $information['processed'];
}
Suppose I have single array of arrays. each element in the array of arrays are similar to each other as they have similar keys, but perhaps one of the keys has a unique value or one of the arrays in the array of arrays has an additional/different key. For example...
$masterArray = array(
[0]=>array(id=>'123', url=>"http://xyz.com", data=>"something", data2=>"else"),
[1]=>array(id=>'123', url=>"http://xyz.com", data=>"something", data3=>"baby"),
[2]=>array(id=>'456', url=>"http://abc.com", data=>"something", data2=>"completely"),
[3]=>array(id=>'456', url=>"http://abc.com", data=>"something", data3=>"different"),
[4]=>array(id=>'789', url=>"http://def.com", data=>"something", data2=>"is not quite"),
[5]=>array(id=>'789', url=>"http://def.com", data=>"something", data3=>"right")
);
I require a new array to be made from $masterArray that would merge the individual keys together in the array of arrays into a new key in the new array, based on matching key value pairs in each individual array.
So the final array would appear like this...
$finalArray = array(
[0]=>array(id=>'123', url=>"http://xyz.com", data=>"something", data2=>"else", data3=>"baby"),
[1]=>array(id=>'456', url=>"http://abc.com", data=>"something", data2=>"completely", data3=>"different"),
[2]=>array(id=>'789', url=>"http://def.com", data=>"something", data2=>"is not quite", data3=>"right"),
);
There's quite an array (no pun intended) of php functions that can sort / merge arrays or values, but I cannot figure out which ones to use or how to implement it!
Can anyone figure out a solution to this? It would be much appreciated.
Note: To note, I have done the following
What I have tried is the following algorithm:
create two copies of $masterArray (call them $m1 and $m2)
use two for..each loops. The first for...each loop goes through $m1, the second one through $m2
grab the current element in $m1 from the outer loop
compare the current element in $m2 from the inner loop
if the $m1[outerloopindex] matches $m2[innerloopindex] through the majority of their key values, create a new array element $x, merging their key value pairs.
push or add $x to $newArray
(and this may or may not work) remove the element compared from $m1 and $m2 (since we used them, we don't need them anymore. assume no more matches)
if the $m1[outerloopindex] does not match$m2[innerloopindex] , simply go to the next $m2[innerloopindex] value and compare again to $m1[outerloopindex] until a match is made (or not)
if no elements in $m2 match the element compared against in $m1, keep $m1[outerloopindex]
loop again going to $m1[outerloopindex+1] etc.
But unfortunately it does not seem to return the correct number of results :(
Sample code is below.
foreach($artistData as $key=>&$asset){
// 2. examine each element, its value is itself an array.
// $key returns the position
// reset the $artistData array
$artistData=array_values($artistData);
$currElement = $artistData[$key];
// 3. check for this secondary array's uid.
// loop through each element in this secondary array
$currElUid = $currElement['uid'];
$currElid = $currElement['id'];
$currElThumbUrl = $currElement['thumbUrl'];
// 4. then proceed down the remaining array and compare the remaining indice's array's uid with the current one being explored
$artistCount=0;
// reset the second array $artistData02;
$artistData02 = array_values($artistData02);
foreach($artistData02 as $key02=>&$asset02){
// clear our temporary new element
unset($resultElement);
$resultElement=array();
// grab the new element to compare to.
// make sure it's not the same as the original
$newCurrElement = $artistData02[$key02];
$newCurrElUid = $newCurrElement['uid'];
$newCurrElid = $newCurrElement['id'];
$newCurrElThumbUrl = $newCurrElement['thumbUrl'];
// if I already compared this element, then skip it entirely
// We also don't want to compare the element to itself.
if ($key!=$key02){
// make sure the uids match
if($currElUid==$newCurrElUid){
// make sure the thumb URLs are different
if($currElThumbUrl!=$newCurrElThumbUrl){
// create the new merged element
// grab the filetype of $currElement
switch($currElement['filetype']){
case 1:
$resultElement['imageLge']=$currElement['publicUrl'];
$resultElement['imageSml']=$currElement['thumbUrl'];
break;
case 3:
$resultElement['song']=$currElement['publicUrl'];
break;
}
// then we compare the newCurrElement and add our information
switch($newCurrElement['filetype']){
case 1:
$resultElement['imageLge']=$newCurrElement['publicUrl'];
$resultElement['imageSml']=$newCurrElement['thumbUrl'];
break;
case 3:
$resultElement['song']=$newCurrElement['publicUrl'];
break;
}
// for the remaining values, we will pass as is
$resultElement['title']=$currElement['title'];
$resultElement['uid']=$currElement['uid'];
// take the resultant $resultElement and merge it to the main array (before $resultELement is recreated)
array_push($resultArr,$resultElement);
// this will reflow the elements, and change the indexing(so the echo merge statement will change). but comparisons will be reduced
unset($artistData[$key]);
$artistData = array_values($artistData);
unset($artistData02[$key02]);
$artistData02 = array_values($artistData02);
}else{
//echo "The thumbURLs are the same. skipping... <br />";
}
}else{
//echo "not the same uids. skipping... <br />";
}
}else{
//echo "this is the same element. skipping... <br />";
}
$artistCount++;
// end inner for...each loop
}
// 7. loop and check through the remaining elements in main array again.
}
/* end outer for each loop */
// add another element - the artist count at the end
$resultArr['artistCount']= $artistCount-1;
// build a JSON object that contains the artists, the total number
echo $resultArr;
again, any help is appreciated...
To answer your original question, this code will intake your masterArray and output your finalArray:
// sample array just for completeness
$masterArray = array(
array('id'=>'123', 'url'=>"http://xyz.com", 'data'=>"something", 'data2'=>"else"),
array('id'=>'123', 'url'=>"http://xyz.com", 'data'=>"something", 'data3'=>"baby"),
array('id'=>'456', 'url'=>"http://abc.com", 'data'=>"something", 'data2'=>"completely"),
array('id'=>'456', 'url'=>"http://abc.com", 'data'=>"something", 'data3'=>"different"),
array('id'=>'789', 'url'=>"http://def.com", 'data'=>"something", 'data2'=>"is not quite"),
array('id'=>'789', 'url'=>"http://def.com", 'data'=>"something", 'data3'=>"right")
);
// here's where the code actually begins
$finalArray = array();
foreach( $masterArray as $m )
{
if( !isset( $finalArray[$m['id']] ) )
$finalArray[$m['id']] = $m;
else
$finalArray[$m['id']] = array_merge( $finalArray[$m['id']], $m );
}
$finalArray = array_values( $finalArray );
If you var_dump $finalArray, it'll line up with what you wanted to get. This is matching based on id.
Your sample code I haven't taken the time to read thoroughly, is aggregating values based on id enough? If so, answer is above. ;)