I am trying to get the union of two collections without overriding any value:
First Collection:
Collection {#246 ▼
#items: array [▼
0 => array [▼
"status" => "Invoice"
"letterPaymentAmount" => 4240.0
"BankAccountNo" => "SEK"
"Date" => "2017-07-15T16:32:22"
"DueDate" => "2017-07-28T00:00:00"
"ocr" => "3000000202"
"lastDatePayDay" => "28"
]]}
Second Collection
Collection {#246 ▼
#items: array [▼
0 => array [▼
"status": "Reminder",
"letterPaymentAmount": 4300,
"BankAccountNo": "SEK",
"Date": "2017-08-15T16:01:30",
"DueDate": "2017-08-30T00:00:00",
"ocr": "3000002406",
"lastDatePayDay": "30",
"lastDatePayMonth": "Aug",
"Country": "Singapore",
"Customer": "TickTack"
]]}
I want to acomplish this:
Collection {#246 ▼
#items: array [▼
0 => array [▼
"status" => "Invoice"
"letterPaymentAmount" => 4240.0
"BankAccountNo" => "SEK"
"Date" => "2017-07-15T16:32:22"
"DueDate" => "2017-07-28T00:00:00"
"ocr" => "3000000202"
"lastDatePayDay" => "28"],
1=> [
"status": "Reminder",
"letterPaymentAmount": 4300,
"BankAccountNo": "SEK",
"Date": "2017-08-15T16:01:30",
"DueDate": "2017-08-30T00:00:00",
"ocr": "3000002406",
"lastDatePayDay": "30",
"lastDatePayMonth": "Aug",
"Country": "Singapore",
"Customer": "TickTack" ]]}
I do not want to override any existing key or value just add them together.
I have tried union() but that overrides the existing keys and does not take keys that do not exist in first collection .
Any help would be much appreciated
Have you used concat()? An example is the following:
$col1 = collect([
['abc' => 1, 'dec' => 2],
['abc' => 1, 'dec' => 6]
]);
$col2 = collect([
['abc' => 3, 'dec' => 4, 'acd' => 2],
['abc' => 1, 'dec' => 8, 'acd' => 6],
]);
return $col1->concat($col2);
Note: if you use this on a collection without nested array then you might get different result from this one.
Use push to add new items to an existing collection without editing items.
$collection = collect([['a' => 'b']]);
$collection2 = collect([['c' => 'd']]);
$collection2->each(function ($e) use (&$collection) {
$collection->push($e);
});
Use merge()
$first = collect(['One','Two']);
$second = collect(['Two','Five']);
$merged = $first->merge($second);
// $merged->all();
Related
I have 2 arrays and I want to merge them. (I can merge them) but I also need to include their unique keys in merged results and that part I cannot achieve.
sample
$prices = [
['112802' => "500000"],
['113041' => "1000000"],
];
$notes = [
['112802' => "note 2"],
['113041' => "note 1"],
];
$collection = collect($prices);
$zipped = $collection->zip($notes);
$zipped->toArray();
Unique keys are 112802 and 113041.
When I merge my array all I get is this:
[
[
"1000000",
"note 1"
],
[
"500000",
"note 2"
]
]
What I'm looking for is like this:
[
[
"id" => "112802",
"price" => "500000",
"note" => "note 2",
],
[
"id" => "113041",
"price" => "1000000",
"note" => "note 1",
]
}]
any suggestion?
This does what you want with the data you provide.
NOTE it will only work if your 2 arrays are the same size and the the keys are in the same order.
If this data comes from a database, it is likely it could have been produced in the format you actually wanted rather than having to fiddle with the data post fetch.
$prices = [
['112802' => "500000"],
['113041' => "1000000"],
];
$notes = [
['112802' => "note 2"],
['113041' => "note 1"],
];
$new = [];
foreach ($prices as $i=>$pr){
$k = key($pr);
$new[] = [ 'id' => $k,
'price' => $pr[$k],
'note' => $notes[$i][$k] ];
}
print_r($new);
RESULT
Array
(
[0] => Array (
[id] => 112802
[price] => 500000
[note] => note 2
)
[1] => Array (
[id] => 113041
[price] => 1000000
[note] => note 1
)
)
Here's another solution using some of Laravel's Collection methods.
It's not the most elegant, but it can be a starting point for you.
$prices = collect([
['112802' => "500000"],
['113041' => "1000000"],
])->mapWithKeys(function($item) {
// This assumes that the key will always be the ID and the first element is the price.
// Everythng else for each element will be ignored.
$id = array_keys($item)[0];
return [$id => ["id" => $id, "price" => reset($item)]];
});
$notes = collect([
['112802' => "note 2"],
['113041' => "note 1"],
])->mapWithKeys(function($item) {
$id = array_keys($item)[0];
return [$id => ["id" => $id, "note" => reset($item)]];
});
$result = $prices->zip($notes)->map(function ($item) {
// Feel free to call `toArray()` here if you don't want a Collection.
return collect($item)->mapWithKeys(function ($a) { return $a; });
});
Below is the $result (called using dd()).
Illuminate\Support\Collection {#1886 ▼
#items: array:2 [▼
0 => Illuminate\Support\Collection {#1888 ▼
#items: array:3 [▼
"id" => 112802
"price" => "500000"
"note" => "note 2"
]
}
1 => Illuminate\Support\Collection {#1889 ▼
#items: array:3 [▼
"id" => 113041
"price" => "1000000"
"note" => "note 1"
]
}
]
}
It's achieved by extracting the ID so that the zip can join there, but then we need a little hack with the map and mapWithKeys in the $result.
That's just because otherwise each element in $result will still have two separate arrays for $prices and $notes.
I am trying to get the value from a collection in PHP.
$todaylog variable contains a collection from a laravel query builder:
$todaylog = [
{
"row_id":55,
"emp_number":"IPPH0004",
"timestamp":"03:30:23",
"attendance_status":"Punch In",
"date_created":"2021-10-01"
},
{
"row_id":56,
"emp_number":"IPPH0004",
"timestamp":"11:32:50",
"attendance_status":"Start Break",
"date_created":"2021-10-01"
},
{
"row_id":57,
"emp_number":"IPPH0004",
"timestamp":"11:33:09",
"attendance_status":"End Break",
"date_created":"2021-10-01"
}
]
What I have done so far: but this approach is so slow:
$timein = DB::table('attendance')->select('timestamp')->where('attendance_status','Punch In')->get();
Now I want to have something like this: (PS this is only a pseudo code)
$timein = (where) $todaylog.attendance_status = "Punch In"
$endbreak = (where) $todaylog.attendance_status = "End Break"
Is this possible? or I have to query them to the database individually? Thanks
What you need in Laravel is something like that:
$rows = collect([
[
"row_id" => 55,
"emp_number" => "IPPH0004",
"timestamp" => "03:30:23",
"attendance_status" => "Punch In",
"date_created" => "2021-10-01"
],
[
"row_id" => 56,
"emp_number" => "IPPH0004",
"timestamp" => "11:32:50",
"attendance_status" => "Start Break",
"date_created" => "2021-10-01"
],
[
"row_id" => 57,
"emp_number" => "IPPH0004",
"timestamp" => "11:33:09",
"attendance_status" => "End Break",
"date_created" => "2021-10-01"
]]);
dd($rows->where('row_id', 57));
Result:
Illuminate\Support\Collection {#446 ▼
#items: array:1 [▼
2 => array:5 [▼
"row_id" => 57
"emp_number" => "IPPH0004"
"timestamp" => "11:33:09"
"attendance_status" => "End Break"
"date_created" => "2021-10-01"
]
]
}
you can use laravel collection where method:
collect($todaylog)->where("attendance_status", "Punch In")->first();
I have he next array looks like:
array:50 [▼
0 => array:39 [▶]
1 => array:39 [▶]
2 => array:39 [▶]
]
So I want to get arrays with a value in common, for example:
array:39 [▼
"id" => 121
"user" => 368
]
array:39 [▼
"id" => 121
"user" => 3687
]
array:39 [▼
"id" => 500
"user" => 452
]
I want to get the two arrays with the attribute
id 121, I was trying to looping the array with foreach looks like:
foreach ($info as $val){
foreach($info as $f ){
if($f["id"]==$val["id"]){
//get the multiple arrays
}
}
}
So, I can't get all the arrays, some idea to how can do that?
I'd use a Collection.
collect your array of arrays:
$collection = collect([
[
"id" => 121
"user" => 368
],
[
"id" => 121
"user" => 3687
],
[
"id" => 500
"user" => 452
]
]);
Use the where method to filter based on a specific key's value:
$filtered = $collection->where('id', 121);
$filtered->all();
/*
[
['id' => '121', 'user' => 368],
['id' => '121', 'user' => 3687],
]
*/
Other where-like methods are available. Be sure to read through all of the documentation on Collections, it's full of great examples!
If you're now convinced that you should use Collections for everything, check out Adam Wathan's awesome book (and other resources): Refactoring to Collections (not free)
Question background
Hello, I have the following array of movie crew members:
array:7 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
1 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ed7"
"department" => "Writing"
"id" => 139098
"job" => "Story"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
2 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5edd"
"department" => "Writing"
"id" => 132973
"job" => "Story"
"name" => "Ben Coccio"
"profile_path" => null
]
3 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ee3"
"department" => "Writing"
"id" => 139098
"job" => "Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
4 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5ee9"
"department" => "Writing"
"id" => 132973
"job" => "Screenplay"
"name" => "Ben Coccio"
"profile_path" => null
]
5 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5eef"
"department" => "Writing"
"id" => 1076793
"job" => "Screenplay"
"name" => "Darius Marder"
"profile_path" => null
]
11 => array:6 [▼
"credit_id" => "52fe49de9251416c750d5f13"
"department" => "Camera"
"id" => 54926
"job" => "Director of Photography"
"name" => "Sean Bobbitt"
"profile_path" => null
]
]
As you can see this is a list of credits I'm getting via the TMDb API. The first step of building the above array was to filter out all jobs that I don't want to display, here's how I did that:
$jobs = [ 'Director', 'Director of Photography', 'Cinematography', 'Cinematographer', 'Story', 'Short Story', 'Screenplay', 'Writer' ];
$crew = array_filter($tmdbApi, function ($crew) use ($jobs) {
return array_intersect($jobs, $crew);
});
My question
I'd like to figure out how to take the above result one step further and combine jobs where the id is the same, so as to end up with something like this, for example:
array:7 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director, Story, Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
I have also considered ditching doing this in my logic and instead doing it in my blade template, but I'm not sure how to achieve that.
How would you accomplish this?
You could nicely use Laravel's Collection in such a situation, which has a great number of methods which will help you in this case.
First, turn this array (the one you already filtered on jobs) to a Collection:
$collection = collect($crew);
Second, group this Collection by it's ids:
$collectionById = $collection->groupBy('id');
Now, the results are grouped by the id and transformed to a Collection in which the keys correspond to the id, and the value an array of 'matching' results. More info about it here.
Finally, just a easy script that iterates through all the results for each id and combines the job field:
$combinedJobCollection = $collectionById->map(function($item) {
// get the default object, in which all fields match
// all the other fields with same ID, except for 'job'
$transformedItem = $item->first();
// set the 'job' field according all the (unique) job
// values of this item, and implode with ', '
$transformedItem['job'] = $item->unique('job')->implode('job', ', ');
/* or, keep the jobs as an array, so blade can figure out how to output these
$transformedItem['job'] = $item->unique('job')->pluck('job');
*/
return $transformedItem;
})->values();
// values() makes sure keys are reordered (as groupBy sets the id
// as the key)
At this point, this Collection is returned:
Collection {#151 ▼
#items: array:4 [▼
0 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5e9d"
"department" => "Directing"
"id" => 139098
"job" => "Director, Story, Screenplay"
"name" => "Derek Cianfrance"
"profile_path" => "/zGhozVaRDCU5Tpu026X0al2lQN3.jpg"
]
1 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5edd"
"department" => "Writing"
"id" => 132973
"job" => "Story, Screenplay"
"name" => "Ben Coccio"
"profile_path" => null
]
2 => array:6 [▼
"credit_id" => "52fe49dd9251416c750d5eef"
"department" => "Writing"
"id" => 1076793
"job" => "Screenplay"
"name" => "Darius Marder"
"profile_path" => null
]
3 => array:6 [▼
"credit_id" => "52fe49de9251416c750d5f13"
"department" => "Camera"
"id" => 54926
"job" => "Director of Photography"
"name" => "Sean Bobbitt"
"profile_path" => null
]
]
}
Note: to use this Collection as an array, use:
$crew = $combinedJobCollection->toArray();
There are multiple ways to achieve this, for example: search the array for overlapping id's, but I think this is the easiest way to achieve this.
Goodluck!
Since you are trying to edit the array elements and its size, I believe array_map() or array_filter() won't be a solution to this.
This is what I could come up with...
$jobs = [
'Director', 'Director of Photography', 'Cinematography',
'Cinematographer', 'Story', 'Short Story', 'Screenplay', 'Writer'
];
$crew = [];
foreach($tmdbApi as $key => $member) {
if($member['id'] == $id && in_array($member['job'], $jobs)) {
if(!isset($crew[$key])) {
$crew[$key] = $member;
} else {
$crew_jobs = explode(', ', $crew[$key]['job']);
if(!in_array($member['job'], $crew_jobs)) {
$crew_jobs[] = $member['job'];
}
$crew[$key]['job'] = implode(', ', $crew_jobs);
}
}
}
Hope this answers your question :)
This is my current output
Collection {#794 ▼
#items: array:8 [▼
"IN" => Collection {#795 ▶}
"NZ" => Collection {#787 ▶}
]}
I want the items to be hold the no of count for each codes like
"IN" => 4,
"NZ" => 3,
I know that I can directly write in a query like this
$query->groupBy('country_code')->orderBy('country_code', 'ASC');
return $query->get([
DB::raw('country_code as country_code'),
DB::raw('COUNT(*) as "count"')
]);
But I want the output from a already queried collection to reduce multiple queries which is a collection.
Right now I am only able to group by on the collection like this
$collection->groupBy('country_code');
$b = $a->groupBy('country_code');
You've done most of the job by proper grouping the data based on the country_code. Now it's just to iterate through the collection with a foreach, key, value and use the collections's count() method to count the number of elements stored under a given country_code
foreach ($b as $countryCode => $items) {
echo $items->count()."\n";
}
Reproduce:
php artisan ti
Psy Shell v0.7.2 (PHP 7.0.8-0ubuntu0.16.04.3 — cli) by Justin Hileman
>>> $cities = collect([['country_code' => 'pl', 'name' => 'Warszawa'], ['country_code' => 'pl', 'name' => 'Wrocław'], ['country_code' => 'de', 'name' => 'Berlin']]);
=> Illuminate\Support\Collection {#846
all: [
[
"country_code" => "pl",
"name" => "Warszawa",
],
[
"country_code" => "pl",
"name" => "Wrocław",
],
[
"country_code" => "de",
"name" => "Berlin",
],
],
}
>>> $grouped = $cities->groupBy('country_code');
=> Illuminate\Support\Collection {#836
all: [
"pl" => Illuminate\Support\Collection {#838
all: [
[
"country_code" => "pl",
"name" => "Warszawa",
],
[
"country_code" => "pl",
"name" => "Wrocław",
],
],
},
"de" => Illuminate\Support\Collection {#837
all: [
[
"country_code" => "de",
"name" => "Berlin",
],
],
},
],
}
>>> foreach ($grouped as $cCode => $cities) {
... echo $cCode . ' has '.$cities->count()."\n";
... }
pl has 2
de has 1