Extract particular array from multidimensional array - php

I have a JSON array of data that I am trying to extract particular value/keys(?) from, and would like to add them into a new array.
The array looks like this:
{ "total':2000,
"achievements":[
{
"id":6,
"achievement":{},
"criteria":{
"id":2050,
"is_completed":false
},
"completed_timestamp":1224053510000
},
{
"id":8,
"achievement":{},
"criteria":{
"id":1289,
"is_completed":true
},
"completed_timestamp":0000000
}
]
}
I want to search for true in the is_completed, and then add the id from that array into a new array.
Basically, find the id's of all the key/array (sorry unsure of terminology) where is_completed is true.
I've tried something simple like finding trying to find the key of an ID, but struggling to get that to work. And also seen some of the multi-level for loop examples but can't get them to work for my data.
Example:
$key = array_search('1289', array_column($array, 'id'));

As pointed out in the comments, you could combine array_filter (to filter completed events) and array_column (to extract their IDs).
$completedAchievements = array_filter(
$array->achievements,
static function (\stdClass $achievement): bool {
return $achievement->criteria->is_completed === true;
}
);
$completedAchievementsIds = array_column($completedAchievements, 'id');
print_r($completedAchievementsIds); // Array([0] => 8)
Note: the code above supposes your JSON was decoded as an object. If it was decoded as an array, just replace -> syntax with the corresponding array index access.
Demo

Related

How do I work with an array object in PHP?

I have a Laravel site I am modifying, but there are some parts of the PHP code I don't quite understand, which are "array objects" or "object arrays". You see, I don't even know what to call them and so can't find a tutorial or basic data on it. Below is the code that I am dealing with:
private function parseMetric($result, $view)
{
$data = collect([]);
$result->each(function($item) use ($data, $view) {
if (isset($item->metric->{$view})) {
$data->push((object)[
'label' => $item->metric->{$view},
'value' => $item->metric->count
]);
}
});
...
From what I can tell, this creates an object out of $result. If I json_encode this and echo it out I get this:
[{"label":"1k-25k","value":14229},
{"label":"1mm+","value":1281},
{"label":"25k-50k","value":398},
{"label":"50k-75k","value":493},
{"label":"75k-100k","value":3848},
{"label":"100k-150k","value":9921},
{"label":"150k-200k","value":4949},
{"label":"200k-250k","value":3883},
{"label":"250k-300k","value":2685},
{"label":"300k-350k","value":2744},
{"label":"350k-500k","value":4526},
{"label":"500k-1mm","value":8690}]
Now this is obviously an array of arrays... or is it? Is it an array of objects? Or is it an object containing arrays? But the most important question is, how do I access and move or change the individual objects/arrays in this object? For example, I want to take the second object/array, which is:
{"label":"1mm+","value":1281}
and move it to the end. How do I do that? How do I find it? I used the following piece of code to find it which is pretty clunky:
$pos = strpos(json_encode($result), '1mm+');
if($pos){
Log::debug('Enrich 73, I found it!!!!!!!!!!!!!!!!!!!!!!!!!!!');
}
And once I find it, how do I move that array/object to the end of the whole object?
And finally, where can I find some kind of tutorial, or documentation, that describes this construct and how to work with it?
There is no need to json_encode the data. Since the data is an instance of Laravel Collection, you can manipulate it like so
$item = $data->firstWhere('label', '1mm+'); // get the item
$data = $data->filter(fn($value, $key) => $value->label !== '1mm+') // remove $item from $data
->push($item); // move $item to the end of data
Acording to Laravel documnentation for Collections, you can try something like this :
To find index of element with name = "1mm+" :
$index = $datas->search(function ($item, $key) {
return $item['name'] == "1mm+";
});
to get an element at a given index :
$element = $datas->get($index);
to Move element at index 3 to the end :
$index = 3
$elementToMove = $data->splice($index, 1);
$datas->push($elementToMove);
Here is a link to the document used : https://laravel.com/docs/8.x/collections

Split Json object into multiple json objects in PHP

I'm a newbie to PHP and I want to split a json object that I have stored in a variable into multiple json objects.
My input looks like this :
{
"results":[
{
"id":"001",
"items":{
"item11":"value1",
"item12":"value2",
"item13":"value3"
},
{
"id":"002",
"items":{
"item21":"value1",
"item22":"value2",
"item23":"value3"
},
{
"id":"003",
"items":{
"item31":"value1",
"item32":"value2",
"item33":"value3"
}]
}
I want to first extract each id and store it into a variable and associate to each id the correspondant json that will look like this :
$id1 = "001";
{
"item11":"value1",
"item12":"value2",
"item13":"value3"
}
Try this loop over each record and save it in result.
$json=json_decode($str,true);
array_map(function($value) use (&$results){
$results[$value['id']]=json_encode($value['items']);
return $results;
}
,$json['results']);
print_r($results);
output
Array (
[001] => {"item11":"value1","item12":"value2","item13":"value3"}
[002] => {"item21":"value1","item22":"value2","item23":"value3"}
[003] => {"item31":"value1","item32":"value2","item33":"value3"} )
if you want to display every array item in results, you can use extract($arr['results'])
but if you want to have specific name you should use loops to do it, depend on your pattren

PHP serializing array as object in JSON [duplicate]

This question already has an answer here:
Array after array_unique function is returned as an object in JSON response [duplicate]
(1 answer)
Closed 3 years ago.
I'm trying to call a REST endpoint that is expecting an object with an array 'campaigns' and a boolean 'getChildren'.
The issue is that the array is sometimes serialized as an object instead of an array.
The incorrect request I'm getting :
{
"campaigns":
{
"1":"1006352",
"2":"1006347",
"3":"1006350",
"4":"1006349",
"5":"1006348",
"6":"1006345",
"7":"1006344",
"8":"1006343"
},
"getChildren":false
}
What I want (and that I get sometimes) :
{
"campaigns":["1006351","1006346"],
"getChildren":false
}
Here is my code :
$campaignIds = array_map(function ($item) use ($networkIds) {
return $item->nid;
},
array_filter($items, function ($item) use ($networkIds) {
return empty((int)$item->nb_shared);
}));
$consoWithoutChildren = EndpointClient::getConsumptionByCampaign($networkIds, $campaignIds);
I want the 'campaigns' parameter to be always interpreted as an array.
I tried json_encode() but it escapes the array, causing issues in the use cases where I had valid JSON, like that :
{"campaigns":"[\"1006351\",\"1006346\"]","getChildren":false}
Any idea what is wrong ?
array_filter keeps the index of the array elements.
So if the first element of your array does not fulfill the condition of your array_filter, you have no element at the 0 index.
To be serialized properly, the array must not have null values in it.
The solution is to reassign the array elements to 0 to n index, with array_values().
Like this :
// array_values is needed to have arrays' indices beginning at 0.
// If not, the JSON parsing would consider the array an object.
// Like {"campaigns":{"1":"1006352","2":"1006347"}}
$campaignIds = array_values(
array_map(
function ($item) use ($networkIds) {
return $item->nid;
},
array_filter(
$items,
function ($item) use ($networkIds) {
return empty((int)$item->nb_shared);
}
)
)
);
$consoWithoutChildren = EndpointClient::getConsumptionByCampaign($networkIds, $campaignIds);

Array_map through a array of objects and grab properties

So I have a var_dump($instagram->get_images()); that gives me the following output:
I want to use array_map to map through all the properties and use them inside a foreach loop later on.. but I'm running into some issues:
Here is the attempt that I have:
$mediaUrls = array_map(function($entry) {
return [
'media_url' => $entry['media_url'],
];
}, $instagram->get_images());
I'm getting back the following error:
Could someone assist me on properly array_mapping through the objects and then later be able to use foreach ($MediaUrls as $media) etc...
The error is correct. You're using array map on an object. But the object does have a ->data property that is an array. But the items in the array are objects, so you'll need to refer to their properties rather than using array syntax.
$images = $instagram->get_images();
$mediaUrls = array_map(function($entry) {
return [
'media_url' => $entry->media_url,
];
}, $images->data);
Couple of suggestions. You said, "I want to use array_map to map through all the properties and use them inside a foreach loop later on."
You can reiterate $images->data later on, so I don't really see the value of making another array just for that purpose
foreach ($images->data as $imageData) {
// do something with $imageData->media_url
}
This would be almost exactly the same as iterating the array you're making with array_map.
foreach ($images->data as $imageData) {
// do something with $imageData['media_url']
}
If you want to get an array of just the urls, you can do it more simply with array_column.
$images = $instagram->get_images();
$mediaUrls = array_column($images->data, 'media_url');
(This won't give you the same result. It will be an array of strings rather than an array of arrays.)

Extract elements from stdClass in PHP dynamically

I have stdClass returned from Laravel ORM result which looks like below,
I know I can access the value using $object->Tables_in_questip3_qgen, but "Tables_in_questip3_qgen" is dynamic. This can change to any string and I would like to extract values only from first element. I would like to have only adj_table,admin_fi and admin_fi_acount values across rows.
In Laravel 5+ you can do this:
collect($object)->map(function ($v) {
return head((array)$v);
});
To get a subarray of arbitrary items (by the order they appear):
$indices = [ 0, 1 ];
collect($object)->map(function ($v) use ($indices) {
$inner = collect($v)->values();
return $inner->only($indices); //This will return the requested indices as a collection, but you can realistically do whatever you want with them like e.g. ->implode or ->toArray
});

Categories