Laravel collection customize - php

Given array like this, I want to arrange data in a custom way.
array:5 [
0 => array:4 [
"message" => "Message number 1 for first conversation"
"is_seen" => 0
"user_id" => 2
"sent_time" => "2017-08-30 23:28:50"
]
1 => array:4 [
"message" => "Message number 2 for first conversation"
"is_seen" => 1
"user_id" => 1
"sent_time" => "2017-08-29 23:36:27"
]
2 => array:4 [
"message" => "Message number 3 for first conversation"
"is_seen" => 1
"user_id" => 1
"sent_time" => "2017-08-29 23:36:27"
]
3 => array:4 [
"message" => "Message number 4 for first conversation by second user"
"is_seen" => 1
"user_id" => 2
"sent_time" => "2017-08-29 23:36:27"
]
4 => array:4 [
"message" => "Message number 5 for first conversation by second user"
"is_seen" => 1
"user_id" => 2
"sent_time" => "2017-08-29 23:36:27"
]
]
What I want to do is to group messages that are sent by the same user so I get an array like this :
$data = [
"block" => [
[
"message" => "Message number 1 for first conversation",
"is_seen" => 0,
"user_id" => 2,
"sent_time" => "2017-08-30 23:28:50"
]
],
"block" => [
[
"message" => "Message number 2 for first conversation",
"is_seen" => 1,
"user_id" => 1,
"sent_time" => "2017-08-29 23:36:27"
],
[
"message" => "Message number 3 for first conversation",
"is_seen" => 1,
"user_id" => 1,
"sent_time" => "2017-08-29 23:36:27"
]
],
"block" => [
[
"message" => "Message number 4 for first conversation by second user",
"is_seen" => 1,
"user_id" => 2,
"sent_time" => "2017-08-29 23:36:27"
],
[
"message" => "Message number 5 for first conversation by second user",
"is_seen" => 1,
"user_id" => 2,
"sent_time" => "2017-08-29 23:36:27"
]
]
];
So basically, If next message user_id is same as previous message user_id add it to group array. If it is not, create new group array and so on. I do not want to group all user messages together since this structure is required for pagination in front-end.

You can do it like this
$new = array();
$prev = "";
$count =0;
foreach($arr as $key=> $value){
if($prev == $value["user_id"]){
$new[$count-1][] = $value;
}else {
$new[$count][] = $value;
$count++;
}$prev = $value["user_id"];
}
print_r($new);
Live demo : https://eval.in/854288

First of all you cannot have duplicate associative keys into the same array however, you group the blocks by some sequential number in the following way:
$group_num = 0;
$col = collect($data);
$col->groupBy(function ($item, $key) use (&$group_num, $col)
{
if (!isset($col[$key - 1]))
return "block_" . $group_num;
if ($item['user_id'] !== $col[$key - 1]['user_id'])
$group_num++;
return "block_" . $group_num;
})
->toArray();
The result it should be something like:
[
"block_0" => [
[
"message" => "Message number 1 for first conversation",
"is_seen" => 0,
"user_id" => 2,
"sent_time" => "2017-08-30 23:28:50",
],
],
"block_1" => [
[
"message" => "Message number 2 for first conversation",
"is_seen" => 1,
"user_id" => 1,
"sent_time" => "2017-08-29 23:36:27",
],
[
"message" => "Message number 3 for first conversation",
"is_seen" => 1,
"user_id" => 1,
"sent_time" => "2017-08-29 23:36:27",
],
],
"block_2" => [
[
"message" => "Message number 4 for first conversation by second user",
"is_seen" => 1,
"user_id" => 2,
"sent_time" => "2017-08-29 23:36:27",
],
[
"message" => "Message number 5 for first conversation by second user",
"is_seen" => 1,
"user_id" => 2,
"sent_time" => "2017-08-29 23:36:27",
],
],
]

Related

Not able to group inner array of the multi-dimensional array

I have an array like this & I need to group an array based on value.
array:3 [
0 => array:5 [
"id" => 1
"maxView" => 0
"maxClick" => 20
"companyName" => "Project A"
"email" => "user1#email.com"
]
1 => array:5 [
"id" => 1
"maxView" => 0
"maxClick" => 20
"companyName" => "Project A"
"email" => "user2#email.com"
]
2 => array:5 [
"id" => 1
"maxView" => 0
"maxClick" => 20
"companyName" => "Project A"
"email" => "user3#email.com"
]
3 => array:5 [
"id" => 1
"maxView" => 0
"maxClick" => 20
"companyName" => "Project B"
"email" => "user1#email.com"
]
4 => array:5 [
"id" => 1
"maxView" => 0
"maxClick" => 20
"companyName" => "Project B"
"email" => "user6#email.com"
]
]
So far, I have following lines of codes. This is grouping my array based on fieldName = companyName But I am not able to add emails belonging to companyname under an array.
foreach ($records as $record) {
if (!array_key_exists($record[$fieldName], $groupedArray)) {
$groupedArray[$record[$fieldName]] = [];
}
$groupedArray[$record[$fieldName]] = $record;
$groupedArray[$record[$fieldName]]['email'] = [];
if (!in_array($record['email'], $groupedArray[$record[$fieldName]]['email'], true)) {
$groupedArray[$record[$fieldName]]['email'][] = $record['email'];
}
}
My code is adding only last email to the array.
"Project A" => [
....
"email" => array:1 [
0 => "user3#email.com"
]
Can anybody help me what I am missing here ?

Yii2 select2 selected one value 2 and more time

I have select2
return $this->form->field($this->model, 'observers')
->widget(Select2::className(),
[
'data' => Tasks::getAllStaffsGroupOffice(),
'disabled' => !$this->can['changeObservers'],
'options' => [
'multiple' => true,
'value' => ArrayHelper::map($this->model->observers, 'staff_id', 'staff_id'),
'placeholder' => Yii::t('tasks_forms', 'FORM_PLACEHOLDER_CHOOSE'),
'class' => 'hiddenInput'
],
'pluginOptions' => [
'allowClear' => true,
'closeOnSelect'=> false,
],
'pluginLoading' => false,
]);
Tasks::getAllStaffsGroupOffice() geting users array by offices. Example ->
array:4 [▼
"main office" => array:1 [▼
2 => "123 123"
]
"office 1" => array:3 [▼
3 => "staff_1"
6 => "staff_2"
2 => "123 123"
]
"office 3" => array:2 [▼
4 => "staff_3"
3 => "staff_1"
]
"office 2" => array:2 [▼
5 => "staff_4"
3 => "staff_1"
]
]
select2 value example -> array (2 => "2")
As a result, the display of the widget itself looks like this
select2 value
How to make it so that the staff which is in 2 and more offices is displayed only 1 time?
I believe you should filter your staff list and then pass it to Select2 widget. My approach for creating a unique array of staff is like this:
$allStaffsGroupOffice = [
"main office" => [
2 => "123 123"
],
"office 1" => [
3 => "staff_1",
6 => "staff_2",
2 => "123 123"
],
"office 3" => [
4 => "staff_3",
3 => "staff_1"
],
"office 2" => [
5 => "staff_4",
3 => "staff_1"
]
];
$repeatedStaff = [];
$newUniqueList = [];
foreach ($allStaffsGroupOffice as $office => $staffList) {
foreach ($staffList as $staffId => $staffName) {
if (!in_array($staffId, $repeatedStaff)) {
$repeatedStaff[] = $staffId;
$newUniqueList[$office][$staffId] = $staffName;
}
}
}
$newUniqueList will be your new array which contains offices with unique staff.

Laravel reverse a collection hierarchy

Say I have a collection that looks like this:
$subscriptions = collect([
[
"id" => 1,
"event" => "FormCompleted",
"subscriber" => [
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com"
]
],
[
"id" => 3,
"event" => "FormCompleted",
"subscriber" => [
"id" => 1928,
"name" => "Pope",
"email" => "pope#dude.com"
],
],
[
"id" => 4,
"event" => "StatusChanged",
"subscriber" => [
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com"
]
]
]);
This shows a list of events with its subscriber. What I want is to re-group this to show a list of subscribers with its events. How do I group these results to get a result like this?
[
[
"id" => 2929,
"name" => "Adam",
"email" => "adam#dude.com",
"subscriptions" => [
[
"id" => 1,
"event" => "FormCompleted"
],
[
"id" => 4,
"event" => "StatusChanged"
],
]
],
[
"id" => 1928,
"name" => "Pope",
"email" => "pope#dude.com",
"subscriptions" => [
[
"id" => 3,
"event" => "FormCompleted"
]
]
]
]
Here is my code... which works, but it is very messy and I feel like there is a better way to do it...
$subscribers = $subscriptions->groupBy('subscriber.id')
->map(function($group) {
$subscriber = $group[0]->subscriber;
$subscriber['subscriptions'] = $group->map(function($subscription) {
unset($subscription['subscriber']);
return $subscription;
});
return $subscriber;
})->values();
I think like that this should return you all subscribers who have groups, so guarantees return not empty subscribers with events
More details you can read this in documention
return Subscriber::has('groups')->get()->groupBy('id');

search for a value array in array in php

In my program i have arrays in the following format . I need to find whether a value is present in an the array
return [
"affiliates" => [
"name" => 'Affiliates',
"value" => 11
],
"business" => [
"name" => 'Business',
"value" => 12
],
"inquiries" => [
"name" => 'Inquiries',
"value" => 13
],
"students" => [
"name" => 'Students',
"value" => 14
],
"teachers" => [
"name" => 'Teachers',
"value" => 15
],
"Personal" => [
"name" => 'Personal',
"value" => 3
],
];
I am doing the following. I am expecting that the search will find the value(12) which is a business, but It is returning false.
$searchcategoryid = '12';
$key = array_search($searchcategoryid, array_column(config('peopletypes.students'), 'value'));
Please note that config('peopletypes.students')will return the array above mentioned. I am using laravel.
You have some sort of configuration problem, this code prints 1.
<?php
$searchcategoryid = '12';
$key = array_search($searchcategoryid, array_column([
"affiliates" => [
"name" => 'Affiliates',
"value" => 11
],
"business" => [
"name" => 'Business',
"value" => 12
],
"inquiries" => [
"name" => 'Inquiries',
"value" => 13
],
"students" => [
"name" => 'Students',
"value" => 14
],
"teachers" => [
"name" => 'Teachers',
"value" => 15
],
"Personal" => [
"name" => 'Personal',
"value" => 3
],
], 'value'));
echo $key;
Try to make sure that your config function actually returns the array you claim it to.

Merging duplicate arrays with count

I'm working with large sets of data and i need to merge the arrays when they are duplicate. If they get merged I need a count added to the array.
array:3721 [▼
0 => array:3 [▼
"subscriber" => "gmail.com."
"code" => 554
"status" => 50
]
1 => array:3 [▼
"subscriber" => "apied.be"
"code" => 550
"status" => 51
]
2 => array:3 [▼
"subscriber" => "beton-dobbelaere.be"
"code" => 550
"status" => 50
]
3 => array:3 [▼
"subscriber" => "live.be"
"code" => 550
"status" => 51
]
4 => array:3 [▼
"subscriber" => "hotmail.be"
"code" => 550
"status" => 51
]
5 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 50
]
6 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 55
]
7 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 51
]
8 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 51
]
This should look something like:
array:3721 [▼
0 => array:3 [▼
"subscriber" => "gmail.com."
"code" => 554
"status" => 50
"amount" => 1
]
1 => array:3 [▼
"subscriber" => "apied.be"
"code" => 550
"status" => 51
"amount" => 1
]
2 => array:3 [▼
"subscriber" => "beton-dobbelaere.be"
"code" => 550
"status" => 50
"amount" => 1
]
3 => array:3 [▼
"subscriber" => "live.be"
"code" => 550
"status" => 51
"amount" => 1
]
4 => array:3 [▼
"subscriber" => "hotmail.be"
"code" => 550
"status" => 51
"amount" => 1
]
5 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 50
"amount" => 1
]
6 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 55
"amount" => 1
]
7 => array:3 [▼
"subscriber" => "telenet.be"
"code" => 550
"status" => 51
"amount" => 2
]
When I merged this example using
array_unique($hardbounces, SORT_REGULAR);
I was left with around 534 results instead of 3721 this is great, only I need to know the amount as well and it has to be somewhat efficient because the result sets can be very big (much bigger).
After it need to be sorted as well to domains and amounts.
I'm using laravel 5.1 if necessary I could turn the array into a collection so helper functions are available
I'm not sure how efficient this code is with really many items (BTW, you did not mention the order of magnitude of the numbers) , but I think it will be more efficient than converting arrays into Laravel collections
$arr = [
0 => [
"subscriber" => "gmail.com.",
"code" => 554,
"status" => 50,
],
1 => [
"subscriber" => "apied.be",
"code" => 550,
"status" => 51,
],
2 => [
"subscriber" => "beton-dobbelaere.be",
"code" => 550,
"status" => 50,
],
3 => [
"subscriber" => "live.be",
"code" => 550,
"status" => 51,
],
4 => [
"subscriber" => "hotmail.be",
"code" => 550,
"status" => 51,
],
5 => [
"subscriber" => "telenet.be",
"code" => 550,
"status" => 50,
],
6 => [
"subscriber" => "telenet.be",
"code" => 550,
"status" => 55,
],
7 => [
"subscriber" => "telenet.be",
"code" => 550,
"status" => 51,
],
8 => [
"subscriber" => "telenet.be",
"code" => 550,
"status" => 51,
],
];
$res = [];
foreach($arr as $element) {
if(empty($res[$element['subscriber']])) {
$res[$element['subscriber']] = [$element, 'count' => 1];
} else {
$res[$element['subscriber']]['count']++;
}
}
var_dump($res);
Try
<?php
$input = array(
0 => array(
"subscriber" => "gmail.com.",
"code" => 554,
"status" => 50),
1 => array(
"subscriber" => "apied.be",
"code" => 550,
"status" => 51),
2 => array(
"subscriber" => "beton-dobbelaere.be",
"code" => 550,
"status" => 50),
3 => array(
"subscriber" => "live.be",
"code" => 550,
"status" => 51),
4 => array(
"subscriber" => "hotmail.be",
"code" => 550,
"status" => 51),
5 => array(
"subscriber" => "telenet.be",
"code" => 550,
"status" => 50),
6 => array(
"subscriber" => "telenet.be",
"code" => 550,
"status" => 55),
7 => array(
"subscriber" => "telenet.be",
"code" => 550,
"status" => 51),
8 => array(
"subscriber" => "telenet.be",
"code" => 550,
"status" => 51)
);
/**
*#param array $counted The array already counted or NULL
*#param array $new The array to count or to merge with the counted $counted
*/
function merge_xor_count(array $counted = NULL, array $new){
if($counted === NULL){
$counted = array();
}
foreach($new as $keyNew => $valueNew){
$matches = false;
foreach($counted as $keyOut => $valueOut){
if ($valueOut['subscriber'] == $valueNew['subscriber'] && $valueOut['code'] == $valueNew['code'] &&
$valueOut['status'] == $valueNew['status']){
$matches = $keyOut;
}
}
if($matches !== false){
$counted[$matches]['amount']++;
}
else{
if(!isset($valueNew['amount'])) $valueNew['amount'] = 1;
$counted[] = $valueNew;
}
}
return $counted;
}
$output = merge_xor_count(NULL, $input);
print_r ($output)."\n";
$output = merge_xor_count($output, $input);
print_r ($output)."\n";
?>
I managed to fix it myself with a foreach loop it runs faster then i expected (0.3179 seconds)
$merged = [];
foreach($hardbounces as &$hardbounce){
if(empty($merged)){
$merged[] = $hardbounce;
}else{
$i = 0;
foreach($merged as $key => $merge){
$i++;
if($hardbounce['subscriber'] == $merge['subscriber'] && $hardbounce['code'] == $merge['code'] && $hardbounce['status'] == $merge['status']){
$merged[$key]['amount']++;
break;
}
if(count($merged) == $i){
$merged[] = $hardbounce;
}
}
}
}
I loop through the bounces, if merged is empty (first iteration) it just adds the hardbounce.
From that point on I will loop through the new array and check if there is a duplicate. When this happens we just add one to the amount and break out of the foreach. Otherwise it will eventually still add duplicates.
After i check if we made it to the last iteration, which means if it still hasn't break-ed we should add the hardbounce because it doesn't exist yet.
To be clear I made sure the amount 1 already exists before this loop runs, instead of adding it during this loop.

Categories