search for duplicates in array with specific value - php

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.

Related

How to call an outside function within a WP loop and get the "next" item, but for specific slugs

In my WordPress child theme workspace, I am trying to learn how to optimize my code below to be more efficient in its PHP process. I have 10 images total that I'm working with. I want any number of these images to be called onto different pages by slug. I know in PHP how to return once from a function, but how do I say in PHP...
"I want photos 1, 2, 6 to go to slugA"
"I want photos 2, 3, 5, 9 to go to slugB"
"I want photos 1, 7 to go to slugC"
etc...
This is what I have so far
//DEFINING ALL MY PHOTOS AND RETURNING THEM
function my_post_photos (
$mQuery = 1,
$image01 = "filler_01.jpg",
$image02 = "filler_02.jpg",
$image03 = "filler_03.jpg",
$image04 = "filler_04.jpg",
$image05 = "filler_05.jpg",
$image06 = "filler_06.jpg",
$image07 = "filler_07.jpg",
$image08 = "filler_08.jpg",
$image09 = "filler_09.jpg",
$image10 = "filler_10.jpg"
): string
{
$vars = get_defined_vars();
foreach ($vars as $key => $value) {
$placeholders[] = get_stylesheet_directory_uri() . '/dist/images/' . $value;
}
return $placeholders[$mQuery];
}
//FURTHER DOWN THIS SAME PAGE...WITHIN MY WP LOOP, CALLING THEM
<?php
$query = new WP_Query($args);
if ($query->have_posts()) :
//WITH THE BELOW $i, I AM FULLY AWARE THAT THE NUMBER OF PHOTOS LOADS IS DEPENDENT ON HOW MANY TIMES MY LOOP CYCLES. I'M COOL WITH THAT BECAUSE I'M EVENTUALLY GOING TO HAVE MORE PHOTOS THAN POSTS.
$i=1;
while ($query->have_posts()) : $query->the_post();
$current_page = sanitize_post($GLOBALS['wp_the_query']->get_queried_object());
$slug = $current_page->post_name;
?>
<?php
if ($slug == "slugA") {
?>
<div>
<h6>
<!-- //THIS FUNCTION LOADS EACH PHOTO PERFECTLY FINE, BUT HOW CAN I ONLY RETURN PHOTOS 1, 2, 6 HERE? -->
<img src="<?php echo my_career_placeholder($i); ?>" border="0" alt="">
</h6>
</div>
<?php
} elseif ($slug = "slugB") {
//HOW CAN I RETURN ONLY PHOTOS 2, 3, 5, 9 HERE?
} elseif ($slug = "slugC") {
//HOW CAN I RETURN ONLY PHOTOS 1, 7 HERE?
}
?>
<?php
$i++;
endif;
endwhile;
endif;
wp_reset_postdata();
?>
Looking at your code as a whole, I think your main function could be rewritten as follows:
function my_post_photos(...$indexes): array
{
$pathPrefix = get_stylesheet_directory_uri().'/dist/images/';
$placeholders = [
$pathPrefix.'filler_01.jpg',
$pathPrefix.'filler_02.jpg',
$pathPrefix.'filler_03.jpg',
$pathPrefix.'filler_04.jpg',
$pathPrefix.'filler_05.jpg',
$pathPrefix.'filler_06.jpg',
$pathPrefix.'filler_07.jpg',
$pathPrefix.'filler_08.jpg',
$pathPrefix.'filler_09.jpg',
$pathPrefix.'filler_10.jpg',
];
$ret = [];
foreach ($indexes as $index) {
if (isset($placeholders[$index])) {
$ret[] = $placeholders[$index];
}
}
return $ret;
}
This would allow you to call it and pass as many indexes in as you want by doing my_post_photos(3,5), which would return an array that you could loop over.
Demo here: https://3v4l.org/8aq6d
Additional optimizations could be done if you truly name your images in that consistent manner, but I'm just keeping this simple for now.
edit
Based on your comments, I think you want to call the function in the loop and get the "next" item, but for the specific slug.
If that's right, one way to do this would be to create a second array that maps slugs to image indexes. You can then use static with that array which means that subsequent calls to the function won't recreate the array, but instead use the first one. Lastly, you can use array_shift which gets you the first item from an array and actually removes that index from the array. (The function array_shift is considered non-performant for large arrays, if I understand things correctly, but I don't think you'll notice that here at all.)
The code below changes this back to returning a string (or null), and can be called repeatadly with a known-slug to get the "next" item. If you'd ever have more posts than images you could take the "next" and append it to the end of the array giving you a circular pool, too.
function my_post_photos(string $slug): ?string
{
$pathPrefix = get_stylesheet_directory_uri().'/dist/images/';
$placeholders = [
$pathPrefix.'filler_01.jpg',
$pathPrefix.'filler_02.jpg',
$pathPrefix.'filler_03.jpg',
$pathPrefix.'filler_04.jpg',
$pathPrefix.'filler_05.jpg',
$pathPrefix.'filler_06.jpg',
$pathPrefix.'filler_07.jpg',
$pathPrefix.'filler_08.jpg',
$pathPrefix.'filler_09.jpg',
$pathPrefix.'filler_10.jpg',
];
// Mapping of slugs to placeholders
// NOTE: This array is created static so that it only ever
// gets created once in the lifetime of the PHP request
static $slugToPlaceholders = [
'slugA' => [1, 2, 6],
'slugB' => [2, 3, 5, 9],
'slugC' => [1, 7],
];
// Unknown slug, return null
if(!isset($slugToPlaceholders[$slug])){
return null;
}
// Grab the next unused index, and remove it from the array
$nextIndex = array_shift($slugToPlaceholders[$slug]);
// Return either the image or nothing if we're out of indexes
return $placeholders[$nextIndex] ?? null;
}
Demo: https://3v4l.org/JDKOH

Very Complex SQL Data Result Merge via PHP (Multi Dimentional Arrays)

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.

Codeigniter retrieve top 5 most occurring rows in column

I currently am using codeigniter 3 to build a website. I have been able to build a full gallery and cart system using the database and active record. As well as a backend. I am currently now working the charts.js to build a pie graph in the backend of the 5 top sellers on the site. As well I will be making a graph for items sold by hour using the line graph. I can make the charts appear with dummy data no problem, however I am running into an issue of trying to retrieve the right data from the DB. It appears the query is going to be quite complex.
My mysql table is named order_items. And in order items there is a column qty and a column product_type. Both return integers. What I need is to find which five items have sold the most quantity. Eventually I will need to add the data to my charts.js setup as follows. Anyone with advanced experience with codeigniter active record?
var pieData = [{
value : 300,
color : "#F7464A",
highlight : "#FF5A5E",
label : "Product 1"
}, {
value : 125,
color : "#46BFBD",
highlight : "#5AD3D1",
label : "Product 2"
}, {
value : 100,
color : "#FDB45C",
highlight : "#FFC870",
label : "Product 3"
}, {
value : 40,
color : "#949FB1",
highlight : "#A8B3C5",
label : "Product 4"
}, {
value : 20,
color : "#4D5360",
highlight : "#616774",
label : "Product 5"
}];
I think you should try this script,
$data = $this->db->select('*')
->from('order_items,SUM(qty) as total_qty')
->order_by('total_qty','desc')
->limit(5)
->group_by('product_id')
->get()->result_array();
I found my own solution using php in case some one else stumbles upon this. If there is a better way to do this using mysql I would be glad to learn something. Here is my php function getting the results I need.
$query = $this -> db -> get('order_items');
$array = array();
foreach ($query -> result() as $result) {
$key = $result -> product_id;
$value = $result -> qty;
if (!isset($array[$key])) {
$array[$key] = $value;
} else if (array_key_exists($key, $array)) {
$old = $array[$key];
$array[$key] = $value + $old;
}
}
arsort($array);
$newArray = array_slice($array, 0, 5, true);
return $newArray;
In the last few hours I have done some mysql tutorials and learned a lot about join, order and limit. Below is what I finally used to get what I needed.
$select = array('products.name as label', 'sum(order_items.qty) as value');
$final = $this -> db -> select($select)
-> from('products')
-> join('order_items', 'order_items.product_id = products.id', 'left')
-> group_by('products.id')
-> order_by('value', 'DESC')
-> limit(5)
-> get() -> result_array();
Try This
$data = $this->db->select('id, product_id, SUM(quantity) as total_qty')
->from('table')
->order_by('total_qty','desc')
->limit(5)
->group_by('product_id')
->get()->result_array();
public function getAllBestsaller() {
$result = array();
$returndata = array();
$this->db->select("*, SUM(total_sale) as total_sale");
$this->db->from("{$this->tblproducts}");
$this->db->where('isactive', 1 );
$this->db->order_by('total_sale','desc');
$this->db->limit(2);
$this->db->group_by('product_id');
$aQuery = $this->db->get();
$this->db->last_query();
if($aQuery -> num_rows() >0 ){
$returndata = $aQuery->result();
}
return $returndata;
}

How to paginate a foreach loop?

I have this foreach loop wich shows the supporters located in the post_meta from a custom post type. What I want to do is add pagination to the foreach loop. I have already found a way to decide how many supporters are shown by slicing the array, but now I am at a loss. And have no idea how to proceed.
Function to get the supporters array
function getSupporters($petitieID){
$support = get_post_meta(get_the_ID(), 'supporters', true);
if (!empty($support)){
return $support;
}}
Function to show the individual supporters in the array
function showSupporters($petitieID){
$supporters = getSupporters($petitieID);
if (!empty($supporters)){
foreach (array_slice($supporters, 0, 2) as $supporter){
$supporterID = $supporter->post_author;
the_author_meta('first_name', $supporterID);
}
}else {
echo 'no votes';
}
}
You could determine which page is currently shown in a GET variable in your address
.../supporters.php?page=1
Then you could set the offset of your array_slice function accordingly
$nItemsPerPage = 2;
$page = isset($_GET['page'])?$_GET['page']:1;
array_slice($supporters, $nItemsPerPage*($page-1), $nItemsPerPage)

Selectively flattening a PHP array according to parent keys

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));
}

Categories