PHP Short arrays based on sub-object value - php

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

Related

How to merge three arrays according to common key in php

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)

How to attach data from one array to another in php

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

get stdclass object array cat_id value?

How to get cat_id ?
Array
(
[0] => stdClass Object
(
[id] => 17
[res_id] => 10
[cat_id] => 3
)
[1] => stdClass Object
(
[id] => 18
[res_id] => 10
[cat_id] => 4
)
[2] => stdClass Object
(
[id] => 52
[res_id] => 19
[cat_id] => 1
)
[3] => stdClass Object
(
[id] => 53
[res_id] => 19
[cat_id] => 3
)
[4] => stdClass Object
(
[id] => 54
[res_id] => 19
[cat_id] => 4
)
I want cat_id from all stdClass Object array.
how can i get this ?
Can anyone help me how do I retrieve the value of cat_id?
Thanks.
Try this
$Your_array
foreach($Your_array AS $Cat){
echo $Cat->cat_id;
}
You can use array_map. For example, if your source array is $array:
$result = array_map(function($x){
return $x->cat_id;
}, $array);
print_r($result);
That will give you:
Array
(
[0] => 3
[1] => 4
[2] => 1
[3] => 3
[4] => 4
)
Demo
$array = array();
$object = new stdClass;
$object->id= "ID";
$object->res_id = "RES_ID";
$object->cat_id = "CAT_ID";
$array[] = $object;
To Access to object attribute:
echo $array[0]->cat_id;
You can replace 0 with index and iterate it in array:
for($index=0;$index<count($array);$index++){
if(isset($array[$index]->cat_id)){
// Do something...
}
}
Object properties in PHP are accessed using the -> syntax. To get the cat_id property of each item in the array, you could loop through the array to get each item one by one, and store the cat_id property of the objects in a new array, like so:
$cat_ids = array();
foreach($array as $item){
$cat_ids[] = $item->cat_id;
}
print_r($cat_ids);
Gives:
Array
(
[0] => 3
[1] => 4
[2] => 1
[3] => 3
[4] => 4
)
If you don't need all the cat_ids, but just the one for a specific object in your original array, you can use
$array[2]->cat_id;
Which would get the cat_id property of the 3rd item in your array.

PHP - Merge 2 arrays of object using a key/id

I want to merge the 2 arrays of objects based on the 'id' field of Array1 and the 'itemVendorCode' of Array2. I also wanted to remove from the resulting arrays of object anything that didn't match.
Array1:
Array
(
[0] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
)
[1] => stdClass Object
(
[id] => 89-575-2354
[qty] => 24
[price] => 230.35
)
[2] => stdClass Object
(
[id] => 89-605-1250
[qty] => 2
[price] => 230.35
)
)
Array2:
Array
(
[0] => Item Object
(
[internalId] => 14062
[itemVendorCode] => 89-605-1250
)
[1] => Item Object
(
[internalId] => 33806
[itemVendorCode] => 89-575-2354
)
[2] => Item Object
(
[internalId] => 64126
[itemVendorCode] => 26-295-1006
)
)
I was able to solve this by this code:
$indexed = array();
foreach($itemsArray as $value) {
$indexed[$value->itemVendorCode] = $value;
}
$results = array();
foreach($vendorItems as $obj) {
$value = $indexed[$obj->id];
if (isset($value)) {
foreach($value as $name => $val) {
$obj->$name = $val;
array_push($results, $obj);
}
}
}
print_r($results);
credits to the original poster. I just modified it a bit,
I was able to get the result like this:
Array
(
[0] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
[internalId] => 2035
[itemVendorCode] => 10-423-1176
)
[1] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
[internalId] => 2035
[itemVendorCode] => 10-423-1176
)
[2] => stdClass Object
(
[id] => 14-102-1010
[qty] => 16
[price] => 3.2
[internalId] => 57033
[itemVendorCode] => 14-102-1010
)
)
I think you will have to use array_map function which provides you a callback function to execute on array(s).
In the callback function:
- declare your array1
- foreach the second array
- set an if statement to check that the current iteration with the id value matches the itemVendorCode of the array2 and return it
something like this:
// You have to specify to PHP to use a local copy of your $array2 to works with it into your callback
$cb = function ($obj1) use ($array2)
{
// you foreach this array
foreach ($array2 as $obj2) {
// if the value of id matches itemVendorCode
if ($obj1->id === $obj2->itemVendorCode) {
// you return the id
return $obj->id;
}
}
};
// this function will fill a new array with all returned data
$mergedArray = array_map($cb, $array1);
This code is a sample but doesn't provide you, your needled solution, try to update it to do what you exactly want ;)

Adding to multidimensional arrays PHP

In my function im storing in $var1 a query from the database of posts. And im storing in $var2 a query from the database of images from the posts. (Each has a key post_id to connect them.)
$var1 will return something like this.
array (
[0] => stdClass Object
(
[post_id] => 210
[post_title] => title
)
[1] => stdClass Object
(
[post_id] => 212
[post_title] => title
)
)
and $var2 will return something like this.
array (
[0] => stdClass Object
(
[post_id] => 210
[post_meta_key] => image
[post_meta_value] => image_value
)
[1] => stdClass Object
(
[post_id] => 212
[post_meta_key] => flag
[post_meta_value] => flag_value
)
[2] => stdClass Object
(
[post_id] => 210
[post_meta_key] => image
[post_meta_value] => image_value
)
[3] => stdClass Object
(
[post_id] => 102
[post_meta_key] => image
[post_meta_value] => image_value
)
)
I would like to create a foreach from $var1 and if $var1[post_id] = $var2[post_id] than $var1 will be edited to something like this
array (
[0] => stdClass Object
(
[post_id] => 210
[post_title] => title
[image] => stdClass Object
(
[0] => image_value
[1] => image_value
)
)
[1] => stdClass Object
(
[post_id] => 212
[post_title] => title
)
)
How can i do this?
foreach ($var1 as &$post1)
{
foreach($var2 as $post2)
{
if ($post1->post_id == $post2->post_id)
{
$post1->image = (object)array(
$post2->post_meta_value
);
}
}
}
Better use arrays instead of objects here:
foreach ($var2 as $key2=>$var2){
if (!empty($var1[$key2])){
$var1[$key2]['image']->$var2;
}
}
You could cast arrays and objects back and forth with
$array = (array)$object;
$object = (object)$array;
This is what you want:
foreach ( $var1 as $v1 )
{
foreach ( $var2 as $v2 )
{
if ( $v1['post_id'] == $v2['post_id'] )
$v1['image'][] = $v2['post_meta_value'];
}
}

Categories