I have following sql query:
SELECT job_id, job_type FROM jobs
I'm getting the following result (set of rows) from mysql query:
RESULT (print_r):
Array
(
[0] => stdClass Object
(
[job_id] => 239
[job_type] => 'type1';
}
[1] => stdClass Object
{
[job_id] => 53
[job_type] => 'type2';
}
[2] => stdClass Object
{
[job_id] => 76
[job_type] => 'type3';
}
[3] => stdClass Object
{
[job_id] => 78
[job_type] => 'type1';
}
)
As you can see I've got three types of job: type1, type2, type3
Is there any way to map/regroup these results by job_type?
Basically I'd like to have something similar to this:
Array
(
['type1'] => Array (
[0] => stdClass Object
{
[job_id] => 239
[job_type] => 'type1';
}
[1] => stdClass Object
{
[job_id] => 76
[job_type] => 'type1';
}
)
['type2'] => Array (
[0] => stdClass Object
{
[job_id] => 53
[job_type] => 'type2';
}
)
['type3'] => Array (
[0] => stdClass Object
{
[job_id] => 78
[job_type] => 'type3';
}
)
)
Or maybe I should use different query?
I've tried to use array_map() with no luck, but I was getting only one array with elements from only one job_type.
Thanks in advance.
You cannot do this with predefined PHP functions. But you can do it yourself pretty easily.
For example: Assuming you have your MySQL result as written in your question in a variable called $rows, you can do the following to get the desired map.
$map = array();
foreach($rows as $row) {
if (!isset($map[$row->job_type])) {
$map[$row->job_type] = array($row);
} else {
$map[$row->job_type][] = $row;
}
}
Now $map contains your desired array.
Unfortunately for this task does not have a native solution in pure PHP/MySQL. So You need to sort it on PHP side manualy. I think You should write function for this an use it when You need
function sortBy($array, $key, $sortKeys=false){
// I don't test this function, just write it for answer, so it may contain errors
$tmp = array();
foreach($array as $k=>$v){
$tmp[$array[$k][$key]][] = $v;
}
if($sortKeys)
ksort($tmp);
return $tmp;
}
And use it like
print_r(sortBy(mySQLSelect(),'job_type'));
Related
I want sorting Teams list by "terminland_days" value
I read same question in Stack Overflow https://stackoverflow.com/a/38237197/5006328 but still have problem on this.
This is my PHP (PHP >=7.4) code:
public function display($tpl = null) {
// myval get from other model
//print_r ($myval);
$myval = Array
(
[0] => stdClass Object
(
[id] => 1
[state] => 1
[teams] => {"teams0":{"name":"Jhon","terminland_days":"3"},"teams1":{"name":"Alex","terminland_days":"2"}}
[distance] => 5839.5147520164
)
[1] => stdClass Object
(
[id] => 2
[state] => 1
[teams] => {"teams0":{"name":"Jeff","terminland_days":"12"},"teams1":{"name":"Fred","terminland_days":"1"}}
[distance] => 5839.5147520164
)
);
foreach ($myval as $item) {
$paramsteam = json_decode($item->teams);
foreach ($paramsteam as $team) {
// i want sorting Teams as "terminland_days" value
usort($team, "compare_func");
// error ==> Warning: usort() expects parameter 1 to be array, object given
echo $team->terminland_days;
}
}
}
public function compare_func($a, $b)
{
if ($a->terminland_days == $b->terminland_days) {
return 0;
}
return ($a->terminland_days < $b->terminland_days) ? -1 : 1;
// You can apply your own sorting logic here.
}
as I understand, I must use usort, please help me how I can do it?
When print_r ($team); output:
stdClass Object
(
[name] => Jhon
[terminland_days] => 3
)
stdClass Object
(
[name] => Alex
[terminland_days] => 2
)
stdClass Object
(
[name] => Jeff
[terminland_days] => 12
)
stdClass Object
(
[name] => Fred
[terminland_days] => 1
)
After a few hours of scrutiny, I realized that the best way was to first convert the object to an array and then sort it. so :
$paramsteam = json_decode($item->teams,true);
usort($paramsteam, function ($item1, $item2) {
return $item1['terminland_days'] <=> $item2['terminland_days'];
});
foreach ($paramsteam as $team) {
echo $team['terminland_days'];
}
also #Nico haase thank you
I've got an object, containing an array of objects, containing an array of values:
stdClass Object (
[devices] => Array (
[0] => stdClass Object (
[location] => 1
[delegate] =>
[type] => 1
[id] => 1234
[IP] => 1.2.3.4
[name] => host1
[owner] => user6
[security] => 15
)
[1] => stdClass Object (
[location] => 2
[delegate] =>
[type] => 1
[id] => 4321
[IP] => 4.3.2.1
[name] => host2
[owner] => user9
[security] => 15
)
)
)
I want to extract just the id and name into an array in the form of:
$devices['id'] = $name;
I considered using the array_map() function, but couldn't work out how to use it... Any ideas?
This will generate you a new array like I think you want
I know you says that delegate is an object but the print does not show it that way
$new = array();
foreach($obj->devices as $device) {
$new[][$device->id] = $device->name;
}
Would something like this not work? Untested but it cycles through the object structure to extract what I think you need.
$devices = myfunction($my_object);
function myfunction($ob){
$devices = array();
if(isset($ob->devices)){
foreach($ob->devices as $d){
if(isset($d->delegate->name && isset($d->delegate->id))){
$devices[$d->delegate->id] = $d->delegate->name;
}
}
}
return($devices);
}
Im usually using this function to generate all child and parent array stdclass / object, but still make key same :
function GenNewArr($arr=array()){
$newarr = array();
foreach($arr as $a=>$b){
$newarr[$a] = is_object($b) || is_array($b) ? GenNewArr($b) : $b ;
}
return $newarr;
}
I have an StdClass Array. Each object is ordered like this (there are about 50 objects in the array, but I thought I'd just put one to show the structure):
stdClass Object (
[display_name] => Bob Simons
[post_title] => Lesson 1
[meta_value] => 100
[comment_approved] => passed
[c_num2] => 26
[term_id] => 3
)
I have another array that looks like this:
Array (
[0] => 3
[1] => 4
[2] => 5
[3] => 16
[4] => 17
[5] => 18
[6] => 19
[7] => 20
[8] => 21
)
The second array defines the sorting of the first one based on the [term_id] field. So essentially, everything with the [term_id] 3 should be at the top of the array, everything with the [term_id] 4 should be next, all based on that second array.
I am trying desperately to figure out how to do this, I've been looking at usort and the like but at a total loss.
I hope someone can help and will be really grateful.
Try this
$sortedArray = [];
foreach ($order as $termId) {
foreach ($objects as $object) {
if ($object->term_id == $termId) {
$sortedArray[] = $object;
}
}
}
$objects holds your stdClass instances and $order your list with the ordered term ids.
In the case the term_id should always order in an ascending way, you can use usort:
usort($objects, function ($obj1, $obj2) {
if ($obj1->term_id == $obj2->term_id) {
return 0;
}
return ($obj1->term_id < $obj2->term_id) ? -1 : 1;
});
I'm having a real headache trying to iterate through an array and output elements. Using the array structure below I want to be able to output each instance of partname.
The following loop outputs the first instance of partname. I can't seem to adapt it to loop through all instances within the array. I'm sure I'm missing something basic.
foreach($ItemsArray['assignments'] as $item) {
$partname = $item['grades'][0]['partname'];
}
Array
(
[assignments] => Array
(
[0] => Array
(
[assigntmentid] => 5101
[grades] => Array
(
[0] => Array
(
[id] => 5101
[name] => Advanced AutoCad
[partid] => 6601
[partname] => Draft
[userid] => 82069
[grade] => 53
[courseid] => 6265
[fullname] => Computer Aided Design
)
)
)
[1] => Array
(
[assigntmentid] => 5101
[grades] => Array
(
[0] => Array
(
[id] => 5101
[name] => Advanced AutoCad
[partid] => 6602
[partname] => Final
[userid] => 82069
[grade] => 35
[courseid] => 6265
[fullname] => Computer Aided Design
)
)
)
)
)
Instead of just coding by slapping the keyboard. Write down what your function needs to do. In english (or whatever language you prefer). This would be something like:
Foreach assignment, loop over all grades and store the partname of
that grade into an array.
And then code it:
function getPartnames($assignments) {
$partNames = array();
foreach ($assignments as $assignment) {
foreach($assignment['grades'] as $grade) {
$partNames[] = $grade['partname'];
}
}
return $partNames;
}
So what did I do? I simply translated english to code.
Some few more tips: Use variables names that make sense. $item; $ItemArray; ... don't make sense. They tell me nothing
use an extra foreach in your loop:
foreach($ItemsArray['assignments'] as $item) {
foreach($item['grades'] as $grade) {
echo $grade['partname'];
}
}
I'm looking for a way to make it so cake returns all database data in the same format/structure... Currently it returns two different types of format depending on the relationship.
If a model 'B' is associated with the current model 'A' being queried it will then place model associations for 'B' underneath it as you can see in [User] below. I want it so that all queries use that structure.
example:
$this->find('all', ....
returns:
Array
(
[0] => Array
(
[UserGroup] => Array
(
[id] => 53
[user_id] => 100003332014851
[media_id] =>
[name] => john
[description] => qwasdfad
)
[User] => Array
(
[id] => 100003332014851
[session_id] => ssm2qbrotmm13ho1ipm8ii2492
[username] =>
[password] => -1
[Planner] => Array
(
)
[Purchase] => Array
(
)
[Listing] => Array
(
)
)
)
I want this to look like:
Array
(
[0] => Array
(
[UserGroup] => Array
(
[id] => 53
[user_id] => 100003332014851
[media_id] =>
[name] => john
[description] => qwasdfad
[User] => Array
(
[id] => 100003332014851
[session_id] => ssm2qbrotmm13ho1ipm8ii2492
[username] =>
[password] => -1
[Planner] => Array
(
)
[Purchase] => Array
(
)
[Listing] => Array
(
)
)
)
)
)
In CakePHP, the find() method return data like your first format. But If you want to format like second one then you have to process it by hand (try to avoid this if possible)
$data = $this->find('all');
$assocs = Set::extract('/User', $data); // extracting all `User` array
foreach($assocs as $key => $assoc) {
unset($data[$key]['User']); // removing the associate `User` from `$data`
$data[$key]['UserGroup']['User'] = $assoc['User']; // adding associate under `UserGroup`
}
ended up doing this... it changes the output to what we need. The top level item does not have a header which is fine I just adjusted our scripts for that... maybe this will help somebody else if they need a custom idea
also no guarantee this covers all possible results but so far it works with all the queries we have.
class AppModel extends Model {
function afterFind($results, $primary) {
//if this is a primary, structure like a secondary so entire site is same format
if ($primary) {
$class = get_class($this);
//simple fix for primary
foreach ($results as $key => $result) {
$result = $this->formatData($result, $class);
$results[$key] = $result;
}
}
return $results;
}
function formatData($result, $class) {
$array = array();
if (isset($result[$class])) {
$array = $result[$class];
unset($result[$class]);
}
$array += $result;
return $array;
}
You can also use contain in this case along with find as UserGroup.User for your desired result