I'm working on a web application that takes its data from a web page using the Yahoo Query Language API to return a JSON array. I've hit a block in that sometimes, when there is only one "race" on the page, the array is setup differently and I can't iterate through it in some circumstances. Let me explain in an example.
Array layout for a page with mutiple races
Array (
[div] => array (
[0] => array (
['venue_id'] = 02222
['venue_name'] = 'Hove'
['race_id'] = 9222
)
[1] => array (
['venue_id'] = 03333
['venue_name'] = 'Romford'
['race_id'] = 2442
)
//...and so on
)
)
Array layout for a page with just one race
Array (
[div] => array (
['venue_id'] = 02222
['venue_name'] = 'Hove'
['race_id'] = 9222
)
)
In the application, I'm currently using a simple foreach statement to iterate through the array. However, this obviously wont work with the second example and I need a workaround.
Example of foreach statement
foreach($result['div'] as $race) {
echo 'Venue ID: '.$race['venue_id'];
echo 'Venue Name: '.$race['venue_name'];
echo 'Race ID: '.$race['race_id'];
}
Any help would be massively appreciated!
Dan
I'd do this..
if(!isset($array['div'][0]))
$array['div'] = array($array['div']);
This way I do not have to have two iteration methods.
Take a look at the count value which is returned with all YQL result sets. If there is only one result, then force it to be an array (with one item) just like when there are multiple results.
So, something likeā¦
if ($yql['query']['count'] == 1) {
$yql['results']['data'] = array($yql['results']['data']);
}
This way, the rest of your script doesn't need to care about the structure of the results.
What about:
if ( isset($result['div'][0])){
//first iteration method
} else{
//second iteration method
}
As simple as:
function format_race($race) {
echo 'Venue ID: '.$race['venue_id'];
echo 'Venue Name: '.$race['venue_name'];
echo 'Race ID: '.$race['race_id']
}
if (isset($result['div']['venue_id'])) {
format_race($result);
} else {
array_map('format_race', $result);
}
This also has the advantage of abstracting the data manipulation in an external function, which can come handy in many situations.
Please note that here I'm abusing a little of array_map, probably using foreach($result as $race) would make your program more readable for other php programmers if all you have to do is just printing.
Related
I am trying to run a function that gets information from a DB and returns an array of the values, so I can then extract it on the page.
Inside the function, after my query I have the following code:
$example_array = array();
while ($row = mysql_fetch_assoc($query) {
$example_array[] = $row;
}
return $example_array;
And there ends my function. Outside of it, I have this:
extract($example_array);
And I would assume I could then directly echo any of the variables that were previously in $example_array, e.g. <?= $example_var ?> but they do not contain any data.
Running print_r($example_array); gives an array that looks like this:
Array ( [0] => Array ( [example_var] => Example String ) )
The start of that code makes me think my array is somehow "lost" inside another array's first ([0]) value, and as such is not extracting correctly.
Have I gone about adding data to that initial $example_array incorrectly?
When you do $example_array[] = $row;, you assign the current row to a new index of $example_array. If you want to access it like $example_array['row_name'], you'd have to assign it like this:
$example_array = $row;
But when you do this, $example_array will be overwritten until it has reached the last row (which means that $example_array will always contain the last row from the query). If you just want the first row, you can do this and skip the whole while loop:
$example_array = mysql_fetch_assoc($query);
Maybe :
$example_array = array();
while ($row = mysql_fetch_assoc($query) {
array_push($example_array, $row['exemple_var']);
}
return $example_array;
The issue is that mysql_fetch_array would have meant $row['row_name'] was valid.
As you added $row to the array $example_array, you now need to access it via it's array id too, such as;
$example_array[0]['row_name'], $example_array[1]['row_name'] etc.
What exactly are you trying to achieve? May be easier to offer assistance if we know.
I have fields in mySQL which is currently being stored like this under the field "tags"
Shopping|Health & Beauty
Coffee|Shopping
What I'm trying to do is to loop through this to create a single dimension array and to grab only the unique values.
I have my query selecting DISTINCT tags from TABLE and run the loop like this:
while ($row_tags = mysql_fetch_assoc($r_tags)) {
$tags = $row_tags['tags'];
$imploded_tags[] = explode("|",$tags);
}
echo "<pre>";
print_r($imploded_tags);
The result from the print_r is showing it as a multidimensional array. I've tried to reexplode it and implode it in different ways, but I haven't been able to get any success. Is there a way that I can create this into a single dimension array? Not all tags will have an equal amount of tags separated by |, so I can't seem to get it to go with a function that I tried from another StackOverflow post. Any help would be greatly appreciated!
OUTPUT:
Array
(
[0] => Array
(
[0] => Shopping
[1] => Health & Beauty
)
[1] => Array
(
[0] => Coffee
[1] => Shopping
)
try this
while ($row_tags = mysql_fetch_assoc($r_tags)) {
$tags = $row_tags['tags'];
$tags = explode("|",$tags);
foreach($tags as $v){
$imploded_tags[] = $v;
}
}
I would do something like:
$imploded_tags = array_merge(explode("|",$tags), $imploded_tags);
}
$imploded_tags = array_unique($imploded_tags);
echo "<pre>";
print_r($imploded_tags);
See the manual on array_merge and array_unique.
However, I do think you are not using the right way to store your tags; they should be stored in a separate table as separate values.
What's going on is when you're fetching your rows from MySQL, you're essentially getting a bunch of data in an array in the first place, which is why you have to loop through them.
With your your implode function, you're taking a bunch of strings, then getting another array set and then appending that to an external array.
If you really wanted to get a single dimensional array without having this multidimensional thing going on, all you really need to do is utilize another loop within that loop.
$all_tags = array();
while ($row_tags = mysql_fetch_assoc($r_tags)) {
$tags = $row_tags['tags'];
$imploded_tags[] = explode("|",$tags);
for($i = 0; $i < count($imploded_tags); $i++) {
$all_tags[] = $imploded_tags[$i]
}
}
print_r($all_tags);
I need help moving through the large array returned by the Facebook PHP SDK. I am trying to find all posts from the user, then also check if the post does/doesn't contain the 'link' key. I have read that it is inefficient to use the foreach loop on arrays of this size due to the copying of the 1MB+ of data to process it. How should I traverse through the information effectively?
The array is structured like this, where 'x' is the number of each post:
Array
(
[data] => Array
(
[x] => Array
(
[from] => Array
(
[name] => james
)
[message] => Thanks for the great interview!
[link] => http://example.com/link.html
[description] => Description here
[etc] => Various other keys possible
)
)
)
Then my current code looks like this where $feed is the array from the Facebook API:
for ($x=0, $y=0; $x<=1000, $y<=19; $x++) {
if (array_key_exists('james', $feed['data'][$x]['from']['name'])) {
if (!array_key_exists('link', $feed['data'][$x])) {
echo "<div>" . $feed['data'][$x]['message'] . "<hr>" . $feed['data'][$x]['description'] . "</div>";
$y++;
};
};
};
I have read about the various iterators but I wouldn't know which to use! Hope you can help me out, cheers, Joe
Speaking about foreach performance
and using array_key_exists in actual fact it's a non sense
imho it's far better like
foreach($feed['data'] as $post){
if($post['from']['name']==='youruser'){
//has user
}
if(isset($post['link'])){
//has link
}
}
put it in the cillosis way
and it should be faster.
You are correct in the fact that foreach can be slow when iterating over large arrays because by default it uses a copy of the value and like you mentioned, that copying can consume memory and take a bit of a time hit.
But, another way to use foreach is by reference which does not create a copy. It works with the original value. This means no matter what size the array is, it won't be placed into memory again. Here is an example of a foreach by reference as shared by another StackOverflow user:
$a = array('hello', 'world');
$asRef =& $a;
$ontime = 0;
foreach($asRef as $i => $v)
{
if (!$ontime++) $a = array('hash', 'the cat');
echo " $i: $v\n";
}
You have the option of using the ArrayIterator from the SPL which is written in C and is pretty fast. Just a quick example of how that would work:
// This would be your large facebook array
$big_array = array(1,2,3,...,10000,10001);
// Get the iterator object
$array_iterator = new ArrayIterator($big_array);
foreach($array_iterator as $item)
{
//Do something with $item here
}
I've not done any benchmarking but I would imagine passing the array by reference and using the ArrayIterator would probably be a good solution.
foreach doesn't always copy. when it does copy, it copies only the immediate data structure being iterated; it doesn't copy any values. for example, if you did
foreach ($arr['data'] as $k => $v) ....
if there were 100 sub elements (you abbreviated one as [x] ), then it would make an array, copy those 100 keys, but would not copy the values that the keys point to, the values being the sub arrays/trees. internally it just stores a pointer and has it point to the subarray's memory address, without copying.
I think you're making a big deal for nothing, as the amount of data that actually gets copied is very little. foreach is almost always very very fast...
if you want to glimpse, look at memory_get_usage() and memory_get_peak_usage() before and after your loop.
I'm parsing some information using Xpath and it returns me a simple array.
$values = array();
Array
(
[0] => http://www.aaa.com/19364328526/
[1] => http://www.bbb.com/207341152011/
[2] => http://www.ccc.co.jp/1246623/
)
Is there any way I can parse through the array and only take certain URLs based on URL weighting? For example. If aaa.com exists, take only aaa.com. If not, check for ccc.co.jp, if that exists, take that only, etc.
I only know how to select from arrays when I know what is there $values[0]/[1]/etc, unfortunately the order of links in this array change and/or aren't present sometimes.
Any help would be much appreciated!
Thanks!
Tre
You can use in_array() to check if a value exists. I don't know exactly what you are trying to do, but here is an example. Do you know all the possible values that you might get back?
//List domains in priority order
$weighted = array('aaa.com','bbb.com','ccc.com');
$selected_url = '';
foreach($weighted as $check) { //start with highest priority
foreach($values as $url) { //loop through all URL's
if(strpos($url,$check) !== false) {
//If a url matches priority, return it. We are finished to exit both loops
$selected_url = $url;
break 2;
}
}
}
$selected_url should have the highest priority URL, or it will be empty if none of the urls were found.
I am checking a list of 10 spots, each spot w/ 3 top users to see if a user is in an array before echoing and storing.
foreach($top_10['top_10'] as $top10) //loop each spot
{
$getuser = ltrim($top10['url'], " users/" ); //strip url
if ($usercount < 3) {
if ((array_search($getuser, $array) !== true)) {
echo $getuser;
$array[$c++] = $getuser;
}
else {
echo "duplicate <br /><br />";
}
}
}
The problem I am having is that for every loop, it creates a multi-dimensional array for some reason which only allows array_search to search the current array and not all combined. I am wanting to store everything in the same $array. This is what I see after a print_r($array)
Array ( [0] => 120728 [1] => 205247 ) Array ( [0] => 232123 [1] => 091928 )
There seems to be more to this code. As there are variables being called in it that aren't defined, such as $c, $usercount, etc.. And using array_search with the 2nd parameter of $array if it doesn't exist is not a good idea also. Since it seems like $array is being set within the if statement for this only.
And you don't seem to be using the $top10 value within the foreach loop at all..., why is this?
It would help to see more of the code for me to be able to help you.