I need to iterate through data pulled from an mssql database twice in my php, but I find that when I perform the first foreach loop the array is then listed as empty as the array pointer has moved through the entire array.
In essence I have this:
$rstGold = $rstGold2 = getFeatured();
foreach($rstGold as $store){
//proccessing here
}
foreach($rstGold2 as $store){
//proccessing here
}
get featured is a sql query returning results using the mssql-PDO driver.
function getFeatured(){
global $db, $debug;
$query = //sql query
return $db->query($query);
}
I need a way to iterate through the results of getFeatured() twice, with them remaining in the same order. My sql query randomizes the results so I cannot perform a second sql query.
While writing this I found a way to perform all of the processing in the same loop, but would still like to know what the best way to do this would be.
Use an ArrayIterator, per the docs:
When you want to iterate over the same array multiple times you need
to instantiate ArrayObject and let it create ArrayIterator instances
that refer to it either by using foreach or by calling its
getIterator() method manually.
And the example follows:
<?php
$fruits = array(
"apple" => "yummy",
"orange" => "ah ya, nice",
"grape" => "wow, I love it!",
"plum" => "nah, not me"
);
$obj = new ArrayObject( $fruits );
$it = $obj->getIterator();
// How many items are we iterating over?
echo "Iterating over: " . $obj->count() . " values\n";
// Iterate over the values in the ArrayObject:
while( $it->valid() )
{
echo $it->key() . "=" . $it->current() . "\n";
$it->next();
}
// The good thing here is that it can be iterated with foreach loop
foreach ($it as $key=>$val)
echo $key.":".$val."\n";
The class also has a method to reset the pointer to the beginning called rewind, used as follows:
$iterator = $arrayobject->getIterator();
$iterator->next();
echo $iterator->key(); //1
$iterator->rewind(); //rewinding to the begining
Hope that helps.
Related
I have an array of arrays, and I am trying to foreach loop through and insert new item into the sub arrays.
take a look below
$newarray = array(
array("id"=>1,"quantity"=>2),
array("id"=>1,"quantity"=>2),
array("id"=>1,"quantity"=>2),
);
foreach($newarray as $item){
$item["total"] = 9;
}
echo "<br>";
print_r($newarray);
The result just give me the original array without the new "total". Why ?
Because $item is not a reference of $newarray[$loop_index]:
foreach($newarray as $loop_index => $item){
$newarray[$loop_index]["total"] = 9;
}
The foreach() statement gives $item as an array: Not as the real value (consuming array). That meaning it can be read but not changed unless you then overwrite the consuming array.
You could use the for() and loop through like this: see demo.
Note: This goes all the way back to scopes, you should look into that.
I have array of data , and base of that I would like to create as many objects as the array have:
I'm trying to do it with foreach loop, but cant crack it.
foreach($file->data as $item){
$entity = new MappedEntity($file,$counter++);
}
it's working but for example array length =5 , It's overriding the value 5 times and as result I'm having one object with values from fifth record, and I would like to create 5 objects with corresponding properties.
Im total newbie to PHP , any suggestions?
This is quite a weird way to behave, but before further knowledge, you can create 5 instances of your class like this:
$i = 1;
foreach ($file->data as $item) {
${"entity_" . $i} = new MappedEntity($file, $counter++);
$i++;
}
//now you have class instances in variables $entity_1, $entity_2 etc...
Or you can store instances to array like this ( preferred way to do this ):
$arr = [];
foreach ($file->data as $item) {
$arr[] = new MappedEntity($file, $counter++);
}
// now you have array with 5 class instances and you can access them with $arr[0], $arr[1] etc...
I have an assignment to do but am having trouble understanding the given psuedocode :/
<?php
$bucket = new array();
print $bucket->addrocks('Rock1')->addrocks('rock2')-
>addrocks('Rock3');
echo "<h1>My Bucket</h1>";
echo "<ul>";
foreach($bucket as $rock){
echo "<li>". $rock ."</li>";
}
echo "</ul>";
?>
Now my trouble starts with understanding how they want me to construct the array after the "print" call? i am not looking for a direct answer to this just maybe a tutorial link or a finger in the right direction
Thank you in advance
In PHP, new is only used for instantiating objects Furthermore, array is a reserved word in PHP, so name your class something else. To instantiate an array in PHP you do this:
$my_array = array();
Now to add items to the array you would do this:
$my_array[] = "Rock 1";
$my_array[] = "Rock 2";
$my_array[] = "Rock 3";
To traverse the array you can use any type of loop, but usually you would just use a foreach loop.
For example:
foreach($my_array as $key => $value) {
echo $value . "<br />";
}
The problem lies in the array construction. This is how one constructs an array in PHP:
one by one:
$bucket = array();
$bucket[] = "Rock1";
$bucket[] = "Rock2";
$bucket[] = "Rock3";
All at once:
$bucket = array("Rock1","Rock2","Rock3");
The documentation: http://php.net/manual/en/language.types.array.php
Well unlikely but may be the array is not an construct but an class in your pseudocode. My assumptions depend on the use of new keyword and the user of -> and addrocks which looks like a method.
So, create a class called array (stupid I know) and get going.
However the user of foreach($bucket) also shows that it expects $bucket to be array. So decide wisely :)
May be use a magic method called __toString() inside the class and return back the array.
All of the methods and iterators that return results from DynamoDB seem to contain the following format (in json style):
{key : [TYPE,value]}
Where 'TYPE' is N,S...
I want them to be in the format:
{key : value}
Where 'value' is a String if S and a number if N (or an array of such if in set form).
The API contains a helper method to format attributes by type from an array:
http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.DynamoDb.DynamoDbClient.html#_formatAttributes
Is there a pre-existing helper method or flag that will do the inverse for results that I've overlooked?
I know implementation of this is somewhat trivial - It just seems to be a bit of work to do the conversion every time I was to use a result.
(here is a naive version providing just the 'N' and 'S' cases)
$iterator = $client->getIterator('Scan',$params);
foreach($iterator as $item){
$newitem = [];
foreach($item as $k => $v){
foreach($v as $type => $actualv){
switch($type){
case 'S' :
$newitem[$k] = $actualv;
break;
case 'N' :
$newitem[$k] = (int)$actualv;
break;
}
}
}
echo json_encode($newitem).PHP_EOL;
}
Is there a method I overlooked to make this easier without having to loop over every key?
[EDIT: Before version 2.4.1 of the SDK,] there isn't a really a pre-existing helper for this, but since your are using getIterator, you can use some iterators magic. Try something like this (building off your original code):
$iterator = $client->getIterator('Scan', $params);
$iterator = new \Guzzle\Iterator\MapIterator($iterator, function ($item) {
return array_map('current', $item);
});
foreach ($iterator as $item) {
// Get a single attribute value
echo $item['attribute_name'] . "\n";
// Print the item attributes
echo print_r($item);
}
EDIT: For version 2.4.1+, you can use the included ItemIterator class that does something similar to what I did with the MapIterator.
$iterator = $client->getIterator('Scan', $params);
$iterator = new \Aws\DynamoDb\Iterator\ItemIterator($iterator);
foreach ($iterator as $item) {
// Get a single attribute value
echo $item['attribute_name'] . "\n";
// Print the item attributes
echo print_r($item->toArray());
}
EDIT: See also Iterating through Amazon DynamoDB Results
I have a PHP array that I'd like to duplicate but only copy elements from the array whose keys appear in another array.
Here are my arrays:
$data[123] = 'aaa';
$data[423] = 'bbb';
$data[543] = 'ccc';
$data[231] = 'ddd';
$data[642] = 'eee';
$data[643] = 'fff';
$data[712] = 'ggg';
$data[777] = 'hhh';
$keys_to_copy[] = '123';
$keys_to_copy[] = '231';
$keys_to_copy[] = '643';
$keys_to_copy[] = '712';
$keys_to_copy[] = '777';
$copied_data[123] = 'aaa';
$copied_data[231] = 'ddd';
$copied_data[643] = 'fff';
$copied_data[712] = 'ggg';
$copied_data[777] = 'hhh';
I could just loop through the data array like this:
foreach ($data as $key => $value) {
if ( in_array($key, $keys_to_copy)) {
$copied_data[$key] = $value;
}
}
But this will be happening inside a loop which is retrieving data from a MySQL result set. So it would be a loop nested within a MySQL data loop.
I normally try and avoid nested loops unless there's no way of using PHP's built-in array functions to get the result I'm looking for.
But I'm also weary of having a nested loop within a MySQL data loop, I don't want to keep MySQL hanging around.
I'm probably worrying about nested loop performance unnecessarily as I'll never be doing this for more than a couple of hundred rows of data and maybe 10 keys.
But I'd like to know if there's a way of doing this with built-in PHP functions.
I had a look at array_intesect_key() but that doesn't quite do it, because my $keys_to_copy array has my desired keys as array values rather than keys.
Anyone got any ideas?
Cheers, B
I worked it out - I almost had it above.I thought I'd post the answer anyway for completeness. Hope this helps someone out!
array_intersect_key($data, array_flip($keys_to_copy))
Use array_flip() to switch $keys_to_copy so it can be used within array_intersect_keys()
I'll run some tests to compare performance between the manual loop above, to this answer. I would expect the built-in functions to be faster but they might be pretty equal. I know arrays are heavily optimised so I'm sure it will be close.
EDIT:
I have run some benchmarks using PHP CLI to compare the foreach() code in my question with the code in my answer above. The results are quite astounding.
Here's the code I used to benchmark, which I think is valid:
<?php
ini_set('max_execution_time', 0);//NOT NEEDED FOR CLI
// BUILD RANDOM DATA ARRAY
$data = array();
while ( count($data) <= 200000) {
$data[rand(0, 500000)] = rand(0, 500000);
}
$keys_to_copy = array_rand($data, 100000);
// FOREACH
$timer_start = microtime(TRUE);
foreach ($data as $key => $value) {
if ( in_array($key, $keys_to_copy)) {
$copied_data[$key] = $value;
}
}
echo 'foreach: '.(microtime(TRUE) - $timer_start)."s\r\n";
// BUILT-IN ARRAY FUNCTIONS
$timer_start = microtime(TRUE);
$copied_data = array_intersect_key($data, array_flip($keys_to_copy));
echo 'built-in: '.(microtime(TRUE) - $timer_start)."s\r\n";
?>
And the results...
foreach: 662.217s
array_intersect_key: 0.099s
So it's much faster over loads of array elements to use the PHP array functions rather than foreach. I thought it would be faster but not by that much!
Why not load the entire result set into an array, then begin processing with nested loops?
$query_result = mysql_query($my_query) or die(mysql_error());
$query_rows = mysql_num_rows($query_result);
for ($i = 0; $i < $query_rows; $i++)
{
$row = mysql_fetch_assoc($query_result);
// 'key' is the name of the column containing the data key (123)
// 'value' is the name of the column containing the value (aaa)
$data[$row['key']] = $row['value'];
}
foreach ($data as $key => $value)
{
if ( in_array($key, $keys_to_copy))
{
$copied_data[$key] = $value;
}
}