count value occurance and group by date - php

I get this date from datebase
Array
(
[0] => Array
(
[page] => login
[timestamp] => 2013-11-06 12:06:30
)
[1] => Array
[page] => changepage
[timestamp] => 2013-11-06 12:06:31
)
and so on..
I want to count the entries from the same day to make
Array
(
[0] => Array
(
[timestamp] => 2013-11-06 // only by the same day..
[count] => 4
)
)
or even
Array
(
[0] => Array
(
[timestamp] => 2013-11-06
[login] => 2
[changepage] => 4
)
)
I've tried
function format($data)
{
$dates = array();
for ($i = 0; $i < count($data); $i++)
{
if ($data[$i]['page'] == 'login')
{
if (!isset($dates[explode(' ', $data[$i]['timestamp'])[0]]))
array_push($dates, array('date' => explode(' ', $data[$i]['timestamp'])[0], 'login' => 1));
else
{
foreach ($dates as $date) {
if ($date['date'] == explode(' ', $data[$i]['timestamp'])[0])
$date['login'] += 1;
}
}
}
return $dates;
}
but that gives me only one record of
Array( Array ( 'timestamp' => '2013-11-06', 'login' => 1) )
In conclosion I want to sum the entries with the same day and same page
(My best solution would be getting 2 arrays one with sum of all the pages and one with detailed page sum)

Here's the solution to your question:
function format($data) {
$result = array();
foreach ($data as $item) {
$date = substr($item['timestamp'], 0, 10);
#$result[$date]['timestamp'] = $date;
#$result[$date][$item['page']]++;
}
sort($result);
return $result;
}
For each item in the array, it first truncates the time part of the timestamp field using substr. Use the date value as the key of the result array, add a timestamp field using this same date value, and increase the value of the other fields (containing page names). I use # operator here to prevent the Notice error when the key (index) doesn't exist yet.
After all items have been processed, sort the result array to change the keys into numeric indices and it becomes a regular array.
Here's the test I run:
$data = array(
array(
'page' => 'login',
'timestamp' => '2013-11-06 12:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 12:06:45'
),
array(
'page' => 'login',
'timestamp' => '2013-11-06 13:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 14:06:45'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-06 14:06:50'
),
array(
'page' => 'login',
'timestamp' => '2013-11-07 12:06:30'
),
array(
'page' => 'changepage',
'timestamp' => '2013-11-07 12:06:45'
)
);
print_r(format($data));
Anda the output is:
Array
(
[0] => Array
(
[timestamp] => 2013-11-06
[login] => 2
[changepage] => 3
)
[1] => Array
(
[timestamp] => 2013-11-07
[login] => 1
[changepage] => 1
)
)
There, hope it helps!

Related

Convert 2d array by specified 2d format

I need to convert the below 2d array in to specified 2d array format. Array contains multiple parent and multiple child array. Also, have tried to convert the code, but am not getting the expected output.
This is the code what i have tried,
$a1 = array(
'0' =>
array(
'banner_details' =>
array(
'id' => 2,
'section_id' => 24
),
'slide_details' =>
array(
0 => array(
'id' => 74,
'name' => 'Ads1'
),
1 => array(
'id' => 2,
'name' => 'Ads2'
)
)
),
'1' =>
array(
'banner_details' =>
array(
'id' => 106,
'section_id' => 92
),
'slide_details' =>
array(
0 => array(
'id' => 2001,
'name' => 'Adv1'
),
1 => array(
'id' => 2002,
'name' => 'Adv2'
)
)
)
);
$s = [];
for($i = 0; $i<2; $i++) {
foreach($a1[$i]['slide_details'] as $vs){
$s[] = $vs;
}
}
My output:
Array
(
[0] => Array
(
[id] => 74
[name] => Ads1
)
[1] => Array
(
[id] => 2
[name] => Ads2
)
[2] => Array
(
[id] => 2001
[name] => Adv1
)
[3] => Array
(
[id] => 2002
[name] => Adv2
)
)
Expected output:
Array
(
[24] => Array
(
[0] => 74
[1] => 2
)
[92] => Array
(
[0] => 2001
[1] => 2002
)
)
please check the above code and let me know.
Thanks,
You can apply next simple foreach loop with help of isset() function:
foreach($a1 as $data){
if (isset($data['banner_details']['section_id'])){
$s[$data['banner_details']['section_id']] = [];
if (isset($data['slide_details'])){
foreach($data['slide_details'] as $row){
$s[$data['banner_details']['section_id']][] = $row['id'];
}
}
}
}
Demo
If you know that indexes like banner_details or slide_details or section_id will be there always then you can skip isset() in if statements.
You can use array_column function for simple solution:
$result = [];
foreach ($a1 as $item)
{
$result[$item['banner_details']['section_id']] = array_column($item['slide_details'], 'id');
}
var_dump($result);

How can match two array in php

I have two array:
One Array
$workingDays = ['2019-11-01','2019-11-02','2019-11-03','2019-11-04'];
Other Array
$doneWork = array(
array(
'id' => 1,
'date' => '2019-11-01',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-02',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-04',
'work' => 'done'
)
);
My Question: How can check which date not exist in $doneWork array
You'd start by extracting the dates from $doneWork using array_map.
$doneWork = [
[
'id' => 1,
'date' => '2019-11-01',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-02',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-04',
'work' => 'done',
],
];
$doneWorkDays = array_map(function ($element) {
return $element['date'];
}, $doneWork);
print_r($doneWorkDays);
Will print:
Array ( [0] => 2019-11-01 [1] => 2019-11-02 [2] => 2019-11-04 )
Then check which elements in $workingDays are not in such array, using array_diff
$diff = array_diff($workingDays, $doneWorkDays);
print_r($diff);
Will print:
Array ( [2] => 2019-11-03 )
Pay attention, the result gives you not only the elements but also their index in the original array. If you don't care about these, use instead:
print_r(array_values($diff));
Why would anyone need such index? Well, perhaps you could need to report not only how many days were missed but also check if two missing elements are adjacent.
(the indexes are relevant only for the array you're comparing against. It doesn't matter in what position they appear in $doneWork )
Edit:
You say you need the results to be in "doneWork" format, which is an associative array with id (always zero), date and work (always 'absent').
Let's say your workin days are now
$workingDays = [
'2019-11-01',
'2019-11-02',
'2019-11-03',
'2019-11-04',
'2019-11-05'
];
So there are two missing days. Again, array map to the rescue:
// from previous answer
$diff = (array_diff($workingDays, $doneWorkDays));
// map each missing date to a doneWork array
$diff_assoc = array_values(
array_map(function($date) {
return [
'id' => 0,
'date' => $date,
'work' => 'absent'
];
},$diff)
);
That will return
Array
(
[0] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[1] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)
Again, note I'm wrapping the result in array_values because you need a plain array as result instead of:
Array
(
[2] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[4] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)
$nonExistingDates = [];
$doneWorkDays = [];
foreach($doneWork as $work) {
$doneWorkDays[] = $work['date'];
}
$nonExistingDates = array_diff($workingDays, $doneWorkDays);
// optional, removes duplicate dates
$nonExistingDates = array_unique($nonExistingDates);

Trying to get each array of unknown amount separately from foreach loop

I'm trying to get each array generated from the following foreach loop so I can then insert them in another array:
function twprp_criteria_field() {
$data = '';
$criteria_string = get_post_meta( 50, 'twprp_site_criteria', true );
$criteria = explode( ',', $criteria_string );
foreach( $criteria as $key => $criterion ) {
$data[] = array(
'id' => sanitize_title_with_dashes( $criterion ),
'title' => $criterion,
'type' => 'slider',
'step' => 0.5,
'min' => 1,
'max' => 10,
'default' => '',
);
}
return $data;
}
This returns:
Array (
[0] => Array ( [id] => hello [title] => Hello [type] => slider [step] => 0.5 [min] => 1 [max] => 10 [default] => )
[1] => Array ( [id] => good-bye [title] => Good Bye [type] => slider [step] => 0.5 [min] => 1 [max] => 10 [default] => )
)
The problem is I need the arrays to be separate but currently they are part of one parent array. I know I can use twprp_criteria_field()[0] and twprp_criteria_field()[1] to get the individual arrays, but I'm returning an unknown number of arrays. I'm sure I'm missing something easy, but I just can't see it.
What you are missing and are looking for is a for loop:
$arr = twprp_criteria_field();
for($i = 0; $i < count($arr); $i++){
echo 'Id:' . $arr[$i]['id'] . " ";
echo 'title:' . $arr[$i]['title'];
// ...
}

PHP usort collections with varying attributes

I have two identical arrays:
$array1 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
$array2 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
I need to merge and sort them in ascending order:
$array1 = array_merge($array1, $array2);
usort($array1, function($value1, $value2) {
if (!array_key_exists('start', $value1) || !array_key_exists('start', $value2)) {
return 0;
}
return $value1['start'] - $value2['start'];
});
However, this doesn't work, and the ordering is incorrect:
Array
(
[0] => Array
(
[start] => 4
[start] => 8
)
[1] => Array
(
[start] => 8
[value] => 4
)
[2] => Array
(
[amount] => 5
)
[3] => Array
(
[start] => 1
[value] => 10
)
[4] => Array
(
[value] => 5
)
[5] => Array
(
[start] => 1
[value] => 10
)
[6] => Array
(
[start] => 4
[value] => 8
)
[7] => Array
(
[start] => 8
[value] => 4
)
)
It should ideally place all items without a start attribute to the start of the array and all items with a start attribute following those in ascending order.
If I remove the arrays that contain no start attribute, it seems to work perfectly. But I need to keep those items without a start attribute. Is there anything I can do with my sort to go around this issue without going through the merged array, removing those that have no start and replacing them after the sort? Ideally I'd love to understand what is happening here to make it fail.
To place the elements without an start key at the front, you have to handle them diffrently in your compare function.
You could try something like this
usort($array1, function($value1, $value2) {
if (!isset($value1['start']) && !isset($value2['start'])) {
return 0;
} else if (!isset($value1['start'])) {
return -1;
} else if (!isset($value2['start'])) {
return 1;
}
return $value1['start'] - $value2['start'];
});

Which PHP Array function should I use?

I have two arrays:
Array
(
[0] => Array
(
[id] => 1
[type] => field
[remote_name] => Title
[my_name] => title
[default_value] => http%3A%2F%2Ftest.com
)
[1] => Array
(
[id] => 2
[type] => field
[remote_name] => BookType
[my_name] => book-type
[default_value] =>
)
[2] => Array
(
[id] => 3
[type] => value
[remote_name] => dvd-disc
[my_name] => dvd
[default_value] =>
)
)
Array
(
[title] => Test
[book-type] => dvd
)
I need to take each key in the second array, match it with the my_name value in the first array and replace it with the corresponding remote_name value of the first array while preserving the value of the second array.
There's got to be some carrayzy function to help!
EDIT: There will also be a few cases that the value of the second array will need to be replaced by the value of the first array's remote_name where the value of the second array matches the value of the first array's my_name. How can I achieve this?
EG: book-type => dvd should turn into BookType => dvd-disc
Like so?:
$first = array(
array(
'id' => 1,
'type' => 'field',
'remote_name' => 'Title',
'my_name' => 'title',
'default_value' => 'http%3A%2F%2Ftest.com',
),
array(
'id' => 2,
'type' => 'field',
'remote_name' => 'BookType',
'my_name' => 'book-type',
'default_value' => '',
),
array(
'id' => 3,
'type' => 'value',
'remote_name' => 'dvd-disc',
'my_name' => 'dvd',
'default_value' => '',
),
);
$second = array(
'title' => 'Test',
'book-type' => 'dvd',
);
$map = array('fields' => array(), 'values' => array());
foreach ($first as $entry) {
switch ($entry['type']) {
case 'field':
$map['fields'][$entry['my_name']] = $entry['remote_name'];
break;
case 'value':
$map['values'][$entry['my_name']] = $entry['remote_name'];
break;
}
}
$new = array();
foreach ($second as $key => $val) {
$new[isset($map['fields'][$key]) ? $map['fields'][$key] : $key] = isset($map['values'][$val]) ? $map['values'][$val] : $val;
}
print_r($new);
Output:
Array
(
[Title] => Test
[BookType] => dvd-disc
)
Explanation:
The first loop collects the my_name/remote_name pairs for fields and values and makes them more accessible.
Like so:
Array
(
[fields] => Array
(
[title] => Title
[book-type] => BookType
)
[values] => Array
(
[dvd] => dvd-disc
)
)
The second loop will traverse $second and use the key/value pairs therein to populate $new. But while doing so will check for key/value duplicates in $map.
Keys or values not found in the map will be used as is.
foreach($arr1 as &$el) {
$el['remote_name'] = $arr2[$el['my_name']];
}
unset($el);
I am not aware of such a carrayzy function, but I know how you could do it:
//$array1 is first array, $array2 is second array
foreach($array1 as $key => $value){
if (isset($value['remote_name'], $value['my_name']) && $value['remote_name'] && $value['my_name']){
$my_name = $value['my_name'];
if (isset($array2[$my_name])) {
$remote_name = $value['remote_name'];
$array2[$remote_name] = $array2[$my_name];
//cleanup
unset($array2[$my_name]);
}
}
}

Categories