Sorry, I have a hard time to write proper thread title for this problem.
Here's my question:
In short: How to merge array item and calculate.
Here's the full explanation
1) I have a (WP custom) database to track statistics: visits, unique visits, etc, and it's stored per post per date.
To make it easier to understand. Here's the screenshot of the table:
2) This is the example data when I queried it:
https://gist.github.com/turtlepod/8e7dc93bae7f0b665fd5aea8a9694998
So in this example we have multiple post ID: "90", "121", & "231"
We have multiple date in db: "2017-03-20", "2017-03-21", "2017-03-22"
We have multiple stats: "visits", and "unique_visits"
We also have a "stat_value" for each item.
Each item have unique ID.
All data is dynamically created when an event happen. so not all post_id have 2 stats or the above date.
Note: keep in mind that in real code, we have a lot more data and variations than the example above.
3) I need to merge the data:
The post_id "121" is the same as post "231", so we need to merge and add the "stat_value" into one data and remove "231" entry.
What is the best way to do this (dynamically) via PHP ?
I have this data:
$raw_data = array( ... ); // the one in github gist
$post_groups = array(
'121' => array( '121', '231' ), // main post_id => array of alias.
);
It need to return the same data format as $raw_data, but remove the data of "231" and include/sum the "stat_value" of "231" to "121".
Thank you.
Try it with this:
function david_transform_data($data, $groups) {
if (empty($groups) === true) {
return $data;
}
// Transform groups into a more useful format
$transformed_groups = array();
foreach ($groups as $post_id => $aliases) {
foreach ($aliases as $alias) {
if (absint($post_id) === absint($alias)) {
continue;
}
$transformed_groups[absint($alias)] = $post_id;
}
}
// Replace aliases with the real post id
foreach ($data as $index => $stat) {
if (isset($transformed_groups[absint($stat->post_id)]) === false) {
continue;
}
$data[$index]->post_id = $transformed_groups[absint($stat->post_id)];
}
// Go through stats and merge those with the same post_id, stat_id
// and stat_date
$merged_stats = array();
$index_tracker = 0;
$stats_hash = array();
foreach ($data as $index => $stat) {
$hash_key = sprintf(
'%s-%s-%s',
$stat->post_id,
$stat->stat_id,
$stat->stat_date
);
if (isset($stats_hash[$hash_key]) === true) {
$merged_stats[$stats_hash[$hash_key]]->stat_value += absint($stat->stat_value);
continue;
}
$merged_stats[] = $stat;
$stats_hash[$hash_key] = $index_tracker;
$index_tracker++;
}
return $merged_stats;
}
var_dump(david_transform_data($raw_data, $post_groups));
There might be a faster solution but this is the first thing that came to my mind.
Related
Using php-mysql, I am fetching data, pushing it into an array. An array consists of 486 records. It's an associative array with 7 column for each record.
When there is a GET request, it works fine. Getting data, binding it to table, chart and dropdown. Everything works fine.
I need to populate dropdown based on selection of another dropdown. And in that case I am making a POST request. And searching in the same array of 486 records.
$temp = Array();
$teamSelectData = Array();
foreach ($allBookingsData as $key => $value) {
if($value['PDG'] == $passedPDG){
array_push($temp, $value["Team_Name"]);
}
}
$tempTeam = array_iunique($temp);
foreach ($tempTeam as $key => $value) {
array_push($teamSelectData, Array(
'name' => $value,
'value' => $key,
'title' => $value
));
}
$returnArray['TeamSelectData'] = $teamSelectData;
// get unique items from array
function array_iunique($array) {
$upper = array_map('strtolower', $array);
return array_intersect_key($array, array_unique($upper));
}
I couldn't able to figure out why is it taking too much time to execute. The comparison if($value['PDG'] == $passedPDG) is the issue or the function array_iunique. And the same way I am populating dropdown for PDG. Based on a selection of PDG, I need to fill dropdown of Team.
How to make this function efficient ?
I'm using codeigniter.
I'm trying to compare some posted values from a form with entries from a database.
Put simply, i want to check to see if the entry is already in the database, if so ignore the posted data, but if there is no database entry then add to the database.
My thinking was that it shouldn't actually be that hard, but having some issues, and now im completely confused. Any pointers in the right direction would be appreciated.
I have an array coming from POST $assigned_ids
And i want to compare that with the data from $assign_data which is being output from the database.
I've been trying foreach loops, looping over the posted data, and then inside that looping through the database and comparing and adding if neccessary.
It works upto a point, but if there is data coming from the database, its adding multiple entires.
Heres my code, surely im over complicating things?
// posted values foreach - loop through all posted values
foreach($assigned_ids as $id) {
if(is_array($assign_data) && count($assign_data) > 0) {
// query all data in assignments table
foreach($assign_data as $key => $value) {
// is the user id from assignments table in posted id's
if(in_array($value->user_id, $id)){
// if it is, then do the course id's match as well? if so, do nothing, already an entry
if($value->course_id == $course_id) {
echo "match id and course, do nothing";
} else {
// else if there isnt an entry for this user for this course, add the entry
$add_data = array(
'user_id' => $value->user_id,
'course_id' => $course_id,
'org_id' => $org_id
);
$this->assignment_model->save_org_assignments($add_data);
}
} else {
// the user id was not in the array from the db, but was in the posted vars, so log in db
$add_data = array(
'user_id' => $id,
'course_id' => $course_id,
'org_id' => $org_id
);
$this->assignment_model->save_org_assignments($add_data);
}
}
} else {
$add_data = array(
'user_id' => $id,
'course_id' => $course_id,
'org_id' => $org_id
);
$this->assignment_model->save_org_assignments($add_data);
}
}
I think your main issue is your array is not properly structured that's why your having a hard time.
My opinion is to predefined your db result after fetching it.
function getAssignedData(){
// its better to get the only field you'll need than to fetch everything
$result = $this->db->select($field)->get();
if($result->num_rows()){
$existing_ids = [];
foreach($result->result() as $row){
$existing_ids[] = $row->$field;
}
return array_flip($existing_ids);
}
return FALSE;
}
And you can already compare the values like this
foreach($assigned_ids as $id)
{
if(!isset($existing_ids[$id])) {
// do something
}
}
Hope that helps.
Hi i need to check an array for users who wrote more then one post. I wanna do that by the user->url because this one is for every user a unique id.
my array looks like:
{
"meta":{
"network":"all",
"query_type":"realtime"
},
"posts":[
{
"network":"facebook",
"posted":"2014-08-16 08:31:31 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Terance Podolski",
"url":"someURL1",
"image":"someURL"
}
},
{
"network":"facebook",
"posted":"2014-08-16 08:30:44 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Ćukasz Podolski",
"url":"someURL2",
"image":"someURL"
}
},
{
"network":"facebook",
"posted":"2014-08-16 08:25:39 +00000",
"sentiment":"neutral",
"url":"someURL",
"user":{
"name":"Terance Podolski",
"url":"someURL1",
"image":"someURL"
}
}
]
}
first i sort the array two times that i only have posts with positive and neutral sentiment and then for the network that i only have posts from facebook. the code looks like that:
$sentimentPosNeu = array();
$sentimentPosNeuFacebook = array();
foreach ( $myarray -> posts as $post ) {
if($post -> sentiment == 'positive' || $post -> sentiment == 'neutral')
$sentimentPosNeu[] = $post;
}
foreach($sentimentPosNeu as $post) {
if($post -> network == 'facebook')
$sentimentPosNeuFacebook[] = $post;
}
now I need all the users who posted more than one time.
I tried but doesn't work:
$unique = array_unique($sentimentPosNeuFacebook);
$dupes = array_diff_key( $sentimentPosNeuFacebook, $unique );
There are several ways that you could do this, but probably the clearest would be to simply add another looping construct that could group the posts by user url. For example:
$groupedPosts = array();
foreach ($sentimentPosNeuFacebook as $post) {
$userUrl = $post->user->url;
if (!isset($groupedPosts[$userUrl]))
$groupedPosts[$userUrl] = array($post);
else
$groupedPosts[$userUrl][] = $post;
}
This will group the array using the user's url as the grouping key. Then, if you wanted to find, for example, the number of posts per user, you could do the following:
$counts = array_map(function($elem) {
return count($elem);
}, $groupedPosts);
If all you want to do is count the number of posts per user, then #girlwithglasses is definitely the better route. However, if you need to do something more complex, hopefully this gives you something to go on!
If you just want to count the number of positive and neutral posts on Facebook by each user, you can do this:
foreach ( $myarray -> posts as $post ) {
if (($post -> sentiment == 'positive' || $post -> sentiment == 'neutral')
&& $post->network == 'facebook')
$poster[$post->user->url]++;
}
If you wanted to keep the posts themselves, instead of incrementing the count by one each time, you could have $poster[$post->user->url] be an array containing each post by that user -- i.e. replace $poster[$post->user->url]++ with $poster[$post->user->url][] = $post in the code above and use count to get the number of posts.
So I have my query, its returning results as expect all is swell, except today my designer through in a wrench. Which seems to be throwing me off my game a bit, maybe its cause Im to tired who knows, anyway..
I am to create a 3 tier array
primary category, sub category (which can have multiples per primary), and the item list per sub category which could be 1 to 100 items.
I've tried foreach, while, for loops. All typically starting with $final = array(); then the loop below that.
trying to build arrays like:
$final[$row['primary]][$row['sub']][] = $row['item]
$final[$row['primary]][$row['sub']] = $row['item]
I've tried defining them each as there own array to use array_push() on. And various other tactics and I am failing horribly. I need a fresh minded person to help me out here. From what type of loop would best suit my need to how I can construct my array(s) to build out according to plan.
The Desired outcome would be
array(
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
)
Something like this during treatment of your request :
if (!array_key_exists($row['primary'], $final)) {
$final[$row['primary']] = array();
}
if (!array_key_exists($row['sub'], $final[$row['primary']])) {
$final[$row['primary']][$row['sub']] = array();
}
$final[$row['primary']][$row['sub']][] = $row['item'];
Something like this....
$final =
array(
'Primary1'=>array(
'Sub1'=>array("Item1", "Item2"),
'Sub2'=>array("Item3", "Item4")
),
'Primary2'=>array(
'Sub3'=>array("Item5", "Item6"),
'Sub4'=>array("Item7", "Item8")
),
);
You can do it using array_push but it's not that easy since you really want an associative array and array_push doesn't work well with keys. You could certainly use it to add items to your sub-elements
array_push($final['Primary1']['Sub1'], "Some New Item");
If I understand you correctly, you want to fetch a couple of db relations into an PHP Array.
This is some example code how you can resolve that:
<?php
$output = array();
$i = 0;
// DB Query
while($categories) { // $categories is an db result
$output[$i] = $categories;
$ii = 0;
// DB Query
while($subcategories) { // $subcategories is an db result
$output[$i]['subcategories'][$ii] = $subcategories;
$iii = 0;
// DB Query
while($items) { // $items is an db result
$output[$i]['subcategories'][$ii]['items'][$iii] = $items;
$iii++;
}
$ii++;
}
$i++;
}
print_r($output);
?>
I need to selectively flatten an array in PHP, but do it selectively. If a key matches a pattern then all sub elements below that key should be included in the 'flat' output.
SO If I had a catalogue of music:
=> array of albums => each of which is an array of song titles
Then I could search for a string, and would get a flat array in reponse. SO if I searched for 'sun' then I would get the entire catalogue for any artist with 'sun' in their name, plus the albums for other artists where 'sun' was in the album name.
Hopefully that makes sense.
Anyone got any thoughts?
Is there a reason you're not using a database to store what sounds like a significant amount of info? It would be fairly simple to write a query in SQL to pull the data out that you want.
Ok, I'm going to assume your data looks like this:
$data = array(
"Bill Withers" => array (
"Lovely Day",
"Use Me",
"Ain't No Sunshine"
),
"Fleet Foxes" => array (
"Sun It Rises",
"White Winter Hymnal"
),
"Billy Joel" => array (
"Piano Man"
)
);
...and that given the input "Bill", you want the output: ["Lovely Day", "Use Me", "Ain't No Sunshine", "Piano Man"]. Here's one way you could do it.
function getSongs($data, $searchTerm) {
$output = array();
foreach ($data as $artist => $songs) {
if (stripos($artist, $searchTerm) !== false)) {
$output = array_merge($output, $songs);
}
}
return $output;
}
...I'll also assume you've got a good reason to not use a database for this.
Do you mean something like that?
$a = array(
"Sunny" => "Bla-bla1",
"Sun" => "Bla-bla2",
"Sunshine" => "Bla-bla3",
);
foreach ($a as $k => $v)
{
// check here whenever you want for $k
// apply something to $v
if ( ... )
$b[$i++] = $v;
}
$sample_data = array(
'artist_name' => array(
'album_name' => array(
'song_name',
'other_mp3_id_info'
)
)
);
function s2($needle,$haystack) {
$threads = array();
foreach ($haystack as $artist_name => $albums) {
if (stripos($artist_name, $needle) !== false)) {
$threads[] = $haystack[$artist_name]; //Add all artist's albums
} else {
foreach ($albums as $album_name => $songs) {
if (stripos($album_name, $needle) !== false)) {
$threads[$artist_name][] = $haystack[$album_name]; //add matching album
}
}
}
}
return $threads;
}
To build off NickF's work, assuming your data looks like his, I'd write the function this way.
function getSongs($data, $searchTerm) {
foreach ($data as $artist => $songs) {
if (stripos($artist, $searchTerm) !== false)) {
$output[$artist] = $songs;
}
}
return $output or null;
}
The results of this function, when no matches are found will obviously return null instead of a blank array; when several matches are found they will then be grouped by their artist. I find direct assignment, $output[$artist] = $songs, to provide more predictable results than array_merge in my own experience. (This also preserves the artist for outputting that data.)
Like NickF said, I would assume you've good reason to not do this with a database? SQL for this would be very simple, such as,
SELECT artist, song FROM songs WHERE artist LIKE '%Bill%' GROUP BY artist;
You can use preg_grep for the searches, be sure to sanitize the input, though:
$matchingArtists = preg_grep('/' . preg_quote($searchString) . '/', array_keys($data));
$matchingSongs = array();
foreach ($data as $artist => $songs) {
$matchingSongs = array_merge($matchingSongs, preg_grep('/' . preg_quote($searchString) . '/', $songs));
}