I am building a [post, comments] project where post details are stored in posts table and comment details are stored in comments table. The project is generated in Laravel(Php). Here is the piece of code.
//get data from Post table
$posts = $this->postsRepo->getAllPosts();
//get data from comments table
$comments = $this->commentRepo->getAllComments();
print_r($posts);
print_r($comments);
The result of post table
Array
(
[0] => stdClass Object
(
[id] => 1
[post_text] => This is a test post
)
)
[1] => stdClass Object
(
[id] => 2
[post_text] => This is another test
)
)
The result of comments table
Array
(
[0] => stdClass Object
(
[id] => 1
[post_id] => 1
[comments_text] => This is a test comment 1
)
[1] => stdClass Object
(
[id] => 2
[post_id] => 1
[comments_text] => This is a test comment 2
)
)
Now I want result like
Array
(
[0] => stdClass Object
(
[id] => 1
[post_title] => This is a test post
[comments] => Array
(
[0] => stdClass Object
(
[id] => 1
[post_id] => 1
[comment_text] => This is a test comment 1
)
[1] => stdClass Object
(
[id] => 2
[post_id] => 1
[comment_text] => This is a test comment 2
)
)
)
)
[1] => stdClass Object
(
[id] => 2
[post_title] => This is another test
[comments] => Array()
)
)
I've used following technique, and it is working
foreach ($posts as $postIndex => $post) {
foreach ($comments as $commentIndex => $comment) {
if($post->id == $comment->post_id) {
$posts[$postIndex]->comments[] = $comment;
}
}
}
There's another way like running comments inside post for loop. I'll send the post_id to comments table. But this technique will be slow, as data increases
Could anybody please suggest a better technology to solve this issue?
Also, I used Repository design pattern for getting posts & comments
There are a couple of ways of doing this, depending on the version of PHP your using (although 1 will always work). The main principle is to index one of the arrays by the ID so that instead of looping over both arrays, you can use an index to set the values. As each post can have multiple comments, it seemed easier to index the posts by the ID and loop over the comments adding them into the correct post...
$posts = [
(object)[
"id" => 1,
"post_text" => "This is a test post"
],
(object)[
"id" => 2,
"post_text" => "This is another test"
]
];
$comments = [(object)
[
"id" => 1,
"post_id" => 1,
"comments_text" => "This is a test comment 1"
],
(object)
[
"id" => 2,
"post_id" => 1,
"comments_text" => "This is a test comment 2"
]
];
$postIndex = array_column($posts, null, "id");
//$postIndex = array_reduce($posts, function ($result, $post) { // PHP pre 7
// $result[$post->id] = $post;
// return $result;
//}, array());
foreach ( $comments as $comment ) {
$postIndex[ $comment->post_id ]->comments[] = $comment;
}
echo "<pre>";
print_r($postIndex);
Outputs...
Array
(
[1] => stdClass Object
(
[id] => 1
[post_text] => This is a test post
[comments] => Array
(
[0] => stdClass Object
(
[id] => 1
[post_id] => 1
[comments_text] => This is a test comment 1
)
[1] => stdClass Object
(
[id] => 2
[post_id] => 1
[comments_text] => This is a test comment 2
)
)
)
[2] => stdClass Object
(
[id] => 2
[post_text] => This is another test
)
)
The only difference is that from PHP 7.0, you can use array_column() with an array of objects. Prior to that you had to manually do the conversion.
You better use eloquent relationships...
but to answer your question for current case, if you need to accomplish this in php way.
// for all the post of the posts array
foreach ($posts as $key => $value) {
// get comments which only belongs to the post
$post_comments = [];
foreach ($comments as $comment) {
if ($comment['post_id'] == $value['id']) {
array_push($post_comments, $comment);
}
}
// add a new attribute (comments) to each post
// set created comments array of the post
$post[$key]['comments'] = $post_comments;
}
If you loop posts then you can use array_intersect and array_intersect_key.
This means you only loop one array once but use array functions to get the correct comments.
This means the arrays have to be arrays and not objects.
Foreach($posts as $key => $post){
$matches = array_intersect(array_column($comments, "post_id"), [$post["id"]]);
$new[$key][] = $post;
$new[$key]["comments"][] = array_intersect_key($comments, $matches);
}
Var_dump($new);
https://3v4l.org/eq20D
Related
So I'm trying to figure out this small piece, but I'm completely stuck and could use some assistance. I will break the code down into sections for understanding.
This will grab 5 of my posts:
$post_list = get_posts([
'post_type' => 'post',
'posts_per_page' => 5,
]);
Output per post:
Array
(
[0] => WP_Post Object
(
[ID] => 59343
)
)
Then I'm adding the returned ID's into an array using the below code:
$post_authors = [];
foreach ($post_list as $key => $post) {
$post_author = \get_post_author($post->ID);
$post_authors[] = $post_author['ID'];
}
print_r($post_authors);
This outputs me the following array:
Array
(
[0] => 52714
[1] => 0
[2] => 3339
[3] => 0
[4] => 0
)
Then I'm matching my custom post author meta associated with the post:
$test_id = [];
foreach ($post_authors as $author) {
$test_id[] = get_post_meta($author, '_test_id');
}
print_r($test_id);
This is the output that I get:
Array
(
[0] => Array
(
[0] => 7899
)
[1] =>
[2] => Array
(
[0] => 3487
)
[3] =>
[4] =>
)
Is there a way that I can map the above posts as keys and then have the id as outputs? Also skip the empty values on get_posts().
For example:
Array
(
[52714] => 7899
[3339] => 3487
)
All help would be appreciated!
If I understand your question correctly then you can use this logic.
$posts = array(5676,6767,0,0,564,898);
$test_id = [];
foreach ($posts as $key =>$value) {
$test_id[$value] = $key; // get_post_meta($author, '_test_id');
}
print_r($test_id);
//output
Array
(
[5676] => 0
[6767] => 1
[0] => 3
[564] => 4
[898] => 5
)
I have three arrays first array include ids and employees name and second array have monthly collection with employee ids and third array have daily collection with employee id and daily collection I want to merge these array with ids and name and dcollection and monthly collection but the desired output is not coming here my first array $ids is
Array
(
[0] => stdClass Object
(
[id] => 1
[name] => Rohit
)
[1] => stdClass Object
(
[id] => 2
[name] => Emop1
)
[2] => stdClass Object
(
[id] => 3
[name] => Pankaj
)
[3] => stdClass Object
(
[id] => 4
[name] => tejpal singh
)
)
second array $q1 is
Array
(
[0] => stdClass Object
(
[name] => Rohit
[id] => 1
[mcollecton] => 100
)
[1] => stdClass Object
(
[name] => Emop1
[id] => 2
[mcollecton] => 1222
)
)
third array $q2 is
Array
(
[0] => stdClass Object
(
[name] => Rohit
[id] => 1
[dcollecton] => 300
)
[1] => stdClass Object
(
[name] => Emop1
[id] => 2
[dcollecton] => 150
)
)
so far what I have tried
$new_array = array();
foreach($ids as $k) {
$q1n = array("id"=>$k->id,"name"=>$k->name);
foreach($q1 as $k1) {
if($k->id==$k1->id){
$mc = array("mc"=>$k1->mcollecton);
array_merge($q1n,$mc);
}
}
foreach($q2 as $k1){
if($k->id==$k1->id){
$dc = array("dc"=>$k1->dcollecton);
array_merge($q1n,$dc);
}
}
$a = array_merge($q1n,$mc);
$av = array_merge($q1n,$dc);
array_push($new_array,$q1n);
}
but the output is coming as
Array
(
[0] => Array
(
[id] => 1
[name] => Rohit
)
[1] => Array
(
[id] => 2
[name] => Emop1
)
[2] => Array
(
[id] => 3
[name] => Pankaj
)
[3] => Array
(
[id] => 4
[name] => tejpal singh
)
)
I want the output be like
Array
(
[0] => Array
(
[id] => 1
[name] => Rohit
[mcollection] => 100
[dcollection] => 300
)
[1] => Array
(
[id] => 2
[name] => Emop1
[mcollection] => 1222
[dcollection] => 150
)
[2] => Array
(
[id] => 3
[name] => Pankaj
[mcollection] => 0
[dcollection] => 0
)
[3] => Array
(
[id] => 4
[name] => tejpal singh
[mcollection] => 0
[dcollection] => 0
)
)
So I have tried many times but the desired output is not coming . please help me out how to get the desired output.
It seemed like that answer could be modified, or put in a function that you could call multiple times if needed to combine more than two arrays.
There's probably cleaner ways to handle this with array functions like array_merge or array_walk, but this is the general idea of how I might approach it. I haven't tested this, but maybe it's useful.
foreach($first as $key1 => $value){
foreach($second as $key2 => $value2){
// match the ids and check if array key exists on first array
if($value['id'] === $value2['id'] && empty($first[$key2])){
$first[$key][$key2] = $value2;
}
}
}
EDIT: Based on the answer you posted vs the question you asked, are you incrementing the collection numbers or just setting them? In other words why use +=? You should also be able to remove array_merge and array_push.
Below is geared more towards what you're trying to do. I haven't tested this either, but if you run into errors, post your code with the errors returned so that it's easier to debug:
foreach($ids as $k)
{
$thisArray = $newArray[] = array("id"=>$k->id,"name"=>$k->name);
foreach($q1 as $k1)
{
if($k->id == $k1->id && !empty($k1->mcollecton))
{
$thisArray['mc'] = $k1->mcollecton;
}
}
foreach($q2 as $k2)
{
if($k->id == $k2->id && !empty($k2->dcollecton))
{
$thisArray['dc'] = $k2->dcollecton;
}
}
}
// This should have both new collections fields on all array items
print_r($newArray)
I need to dynamically produce child elements of an array, these are arrays them selves. So the end result should be (this is a simplified version of the code below to make it easier to understand):
Array
(
[id] => 5000038642
[name] => TrackVia Legacy Section of Array
[description] =>
[table_id] => 5000005024
[records] => Array
(
[0] => Array
(
[id] => 1
[table_id] => 1
[fields] => Array
(
[Name] => First Item
)
)
[1] => Array
(
[id] => 1
[table_id] => 1
[fields] => Array
(
[Name] => Second Item
)
)
)
)
The nested arrays within Results are produced dynamically from a MySQL table, so >
$allItems = array();
$item = array();
// Get each result and build the arrya
while($row = $resultAvailableBoxes->fetch_assoc()) {
$item = array (
"id"=> $row['id'],
"table_id"=> $row['id'],
"fields"=> array (
"Name"=> $row['box_title'],
)
);
// Append the arrays on to each other
$allItems[] = array_merge($allItems, $item);
}
// Place the arrays within the "parent" array
$completeArray = array(
"id"=> 1000,
"name"=> "Sample",
"description"=> "",
"table_id"=> 1000,
"records"=>
$allItems
);
As you can see I am then also trying to append each new array on to the last, before placing those arrays in to the "parent" array. This is where the problems happen.
Using the method
$allItems[] = array_merge($allItems, $item);
I get every array appended on to the last, but then again and again. Like this:
Array
(
[id] => 5000038642
[name] => TrackVia Legacy Section of Array
[description] =>
[table_id] => 5000005024
[records] => Array
(
[0] => Array
(
[id] => 1
[table_id] => 1
[fields] => Array
(
[Name] => Texan BBQ 1
)
)
[1] => Array
(
[0] => Array
(
[id] => 1
[table_id] => 1
[fields] => Array
(
[Name] => Texan BBQ 1
)
)
[id] => 9
[table_id] => 9
[fields] => Array
(
[Name] => Goan Sorpotel with Pea & Mint Pilau and Tomato Chutney
)
)
)
)
When I have 20 items, you can see this would become massive list and just doesn't work. Using the method
$allItems = array_merge($allItems, $item);
Returns only the last array being appended (i.e. it always overwrites whats already in the "allItems" array.
I have also used a simple method that I didn't expect to work, and sure enough it didnt:
$allItems .= $item;
I've come to the conclusion after reading these stackover flow questions which seem like the same thing but aren't or give weird results that I must be approaching this all wrong. Is this the wrong method full stop, or is it that I have missed something out to stop the child elements being continually added?
Appending Arrays (Stack Overflow)
Can't concatenate 2 arrays in PHP
I've lost count of the other questions I've look at on this, including the PHP manual but I can't find anything more relevant the arrays_merge
why don't you just do this?
$items = array();
while($row = $resultAvailableBoxes->fetch_assoc()) {
$items[] = array (
"id"=> $row['id'],
"table_id"=> $row['id'],
"fields"=> array (
"Name"=> $row['box_title'],
)
);
}
// Place the arrays within the "parent" array
$completeArray = array(
"id"=> 1000,
"name"=> "Sample",
"description"=> "",
"table_id"=> 1000,
"records"=> $items
);
this should create an array with all the items and then add it to the $completeArray
Try to use $allItems[] = $item; instead of $allItems[] = array_merge($allItems, $item);
From the database I get the data in the following style:
Array
(
[0] => stdClass Object
(
[id] => 2
[name] => edit_sites
)
[1] => stdClass Object
(
[id] => 1
[name] => view_sites
)
)
Does Laravel have any built-in methods for obtaining data by the keys like this:
Array
(
[id] => Array
(
[0] => 1
[1] => 2
)
[name] => Array
(
[0] => view_sites
[1] => edit_sites
)
)
or i need to do it by myself ?
Unfortunately, there is none, you have to do it by yourself albeit an easy one really.
$processedData = array();
foreach($dbData as $row) {
foreach($row as $dbKey => $value) {
$processedData[$dbKey][] = $value;
}
}
If you're getting the data back as a raw array (which you seem to be), then array_pluck will do most of what you want:
For example:
// you could use this wherever you needed the specific lists
$ids = array_pluck($results, 'id'); // [ 1, 2 ]
// or if you wanted the array exactly as asked for in the question:
$sortedArray = array(
'id' => array_pluck($results, 'id'),
'name' => array_pluck($results, 'name')
);
// [
// 'id' => [1,2],
// 'name' => [ 'view_sites', 'edit_sites' ]
// ]
If you are getting the results as some kind of Illuminate\Support\Collection class (say, from an Eloquent query), then you can use the lists method on the Collection as an alias to array_pluck
$results->lists('id'); // [ 1, 2 ]
I have an array where contains simple objects. The array I have looks like the following:
[posts] => Array
(
[0] => WP_Post Object
(
[ID] => 4
[post_title] => Post #4
...
)
[1] => WP_Post Object
(
[ID] => 100
[post_title] => Post #100
...
)
[2] => WP_Post Object
(
[ID] => 1
[post_title] => Post #1
...
)
[3] => WP_Post Object
(
[ID] => 21
[post_title] => Post #21
...
)
)
also I have an array that contains the first array posts ID in the order I like to show that posts. Lets say that the array map likes like that:
[map] => Array
(
[0] => 4
[1] => 21
[2] => 100
[3] => 1
)
Now the quation. Can I order the array that contains the objects, based on each object ID Property by using as a map the Map array, in order to have a result that will look like this:
[posts] => Array
(
[0] => WP_Post Object
(
[ID] => 4
[post_title] => Post #4
...
)
[1] => WP_Post Object
(
[ID] => 21
[post_title] => Post #21
...
)
[2] => WP_Post Object
(
[ID] => 100
[post_title] => Post #100
...
)
[3] => WP_Post Object
(
[ID] => 1
[post_title] => Post #1
...
)
)
PHP has a builtin way to do this, using the array_multisort function:
$col = array();
foreach ($posts as $post) {
$col[] = array_search($post->ID, $map);
}
array_multisort($col, $posts);
// now $posts is sorted in the order specified in $map
Try it here: http://codepad.org/5rqncj3B
My solution maybe isn't efficient, but it's simple:
function find_post_by_id($posts, $id) {
foreach($posts as $post) {
if ($post->id == $id) {
return $post;
}
}
// error handling here
}
$sorted_posts = array();
foreach($map as $id) {
$sorted_posts[] = find_post_by_id($posts, $id);
}