Restructure an array of events in PHP combining attendees with common location - php

I have a PHP array that holds the dates, locations and time a person will be attending an event. It starts in this format (The original array is always delivered in date/time order):
array(2) {
[0]=>
array(2) {
["date"]=>
string(8) "1st June"
["events"]=>
array(4) {
[0]=>
array(3) {
["location"]=>
string(7) "Venue A"
["name"]=>
string(4) "Pete"
["time"]=>
string(6) "4.00pm"
}
[1]=>
array(3) {
["location"]=>
string(7) "Venue A"
["name"]=>
string(4) "John"
["time"]=>
string(6) "4.30pm"
}
[2]=>
array(3) {
["location"]=>
string(7) "Venue B"
["name"]=>
string(5) "Chris"
["time"]=>
string(6) "7.30pm"
}
[3]=>
array(3) {
["location"]=>
string(7) "Venue A"
["name"]=>
string(4) "Mark"
["time"]=>
string(6) "8.00pm"
}
}
}
[1]=>
array(2) {
["date"]=>
string(8) "2nd June"
["events"]=>
array(4) {
[0]=>
array(3) {
["location"]=>
string(7) "Venue B"
["name"]=>
string(4) "Fred"
["time"]=>
string(6) "5.00pm"
}
[1]=>
array(3) {
["location"]=>
string(7) "Venue C"
["name"]=>
string(5) "Boris"
["time"]=>
string(6) "6.00pm"
}
[2]=>
array(3) {
["location"]=>
string(7) "Venue A"
["name"]=>
string(6) "Rupert"
["time"]=>
string(6) "7.00pm"
}
[3]=>
array(3) {
["location"]=>
string(7) "Venue A"
["name"]=>
string(5) "David"
["time"]=>
string(6) "9.00pm"
}
}
}
}
What I need to do is combine this so attendees at the same location are grouped together where another attendee in a different location doesn't break up the list. So the above array would be changed to this:
array(2) {
[0]=>
array(2) {
["date"]=>
string(8) "1st June"
["events"]=>
array(3) {
[0]=>
array(2) {
["location"]=>
string(7) "Venue A"
["attendees"]=>
array(2) {
[0]=>
array(2) {
["name"]=>
string(4) "Pete"
["time"]=>
string(6) "4.00pm"
}
[1]=>
array(2) {
["name"]=>
string(4) "John"
["time"]=>
string(6) "4.30pm"
}
}
}
[1]=>
array(2) {
["location"]=>
string(7) "Venue B"
["attendees"]=>
array(1) {
[0]=>
array(2) {
["name"]=>
string(5) "Chris"
["time"]=>
string(6) "7.30pm"
}
}
}
[2]=>
array(2) {
["location"]=>
string(7) "Venue A"
["attendees"]=>
array(1) {
[0]=>
array(2) {
["name"]=>
string(4) "Mark"
["time"]=>
string(6) "8.00pm"
}
}
}
}
}
[1]=>
array(2) {
["date"]=>
string(8) "2nd June"
["events"]=>
array(3) {
[0]=>
array(2) {
["location"]=>
string(7) "Venue B"
["attendees"]=>
array(1) {
[0]=>
array(2) {
["name"]=>
string(4) "Fred"
["time"]=>
string(6) "5.00pm"
}
}
}
[1]=>
array(2) {
["location"]=>
string(7) "Venue C"
["attendees"]=>
array(1) {
[0]=>
array(2) {
["name"]=>
string(5) "Boris"
["time"]=>
string(6) "6.00pm"
}
}
}
[2]=>
array(2) {
["location"]=>
string(7) "Venue A"
["attendees"]=>
array(2) {
[0]=>
array(2) {
["name"]=>
string(6) "Rupert"
["time"]=>
string(6) "7.00pm"
}
[1]=>
array(2) {
["name"]=>
string(5) "David"
["time"]=>
string(6) "9.00pm"
}
}
}
}
}
}
So here's how I've figured out to do it juggling variables and stepping through the original array:
// $eventsArray holds the original array data a per the first example
$newArray = array();
foreach($eventsArray as $day) {
$curLocation = '';
$todaysEvents = array();
$teKey = -1;
foreach($day['events'] as $event) {
if($curLocation==$event['location']) {
$todaysEvents[$teKey]['attendees'][] = array(
'name' => $event['name'],
'time' => $event['time']
);
} else {
$todaysEvents[] = array(
'location' => $event['location'],
'attendees' => array(
array(
'name' => $event['name'],
'time' => $event['time']
)
)
);
$teKey = $teKey + 1;
}
$curLocation=$event['location'];
}
$newArray[] = array(
'date' => $day['date'],
'events' => $todaysEvents
);
}
And this works! So why am I asking a question on Stack? Because this feels awfully clunky and I'm not convinced there isn't a much more efficient way of doing it. I get the feeling I'm adding overhead here where it's not necessary.

Here's an alternative version using some PHP 7 (7.3+) features:
$resultEvents = [];
foreach ($events as ['date' => $date, 'events' => $dayEvents]) {
$resultDayEvents = ['date' => $date, 'events' => []];
foreach ($dayEvents as ['location' => $location, 'name' => $name, 'time' => $time]) {
$attendee = ['name' => $name, 'time' => $time];
if ($location === ($previousLocation ?? null)) {
$resultDayEvents['events'][array_key_last($resultDayEvents['events'])]['attendees'][] = $attendee;
} else {
$resultDayEvents['events'][] = ['location' => $location, 'attendees' => [$attendee]];
}
$previousLocation = $location;
}
$resultEvents[] = $resultDayEvents;
}
Demo: https://3v4l.org/bC4LK

You can use references like a cursor to keep track of the last event processed. Less effort to compare location and add attendees. But that comes with the complexity of getting rid of it properly.
Also, but a minor thing is to use strict comparisons... Can avoid some frustrating moments by being more predectible...
// $eventsArray holds the original array data a per the first example
$newArray = array();
foreach($eventsArray as $day) {
$todaysEvents = array();
$curEvent = null;
foreach($day['events'] as $event) {
if($curEvent===null || $curEvent['location']!==$event['location']) {
unset($curEvent);
$curEvent = array(
'location' => $event['location'],
'attendees' => array()
);
$todaysEvents[] = &$curEvent;
}
$curEvent['attendees'][] = array(
'name' => $event['name'],
'time' => $event['time']
);
}
unset($curEvent);
$newArray[] = array(
'date' => $day['date'],
'events' => $todaysEvents
);
}

Related

PHP Convert multidimensional array key to be array multidimensional value

I have problem formatting array to become fancytree format, below array output from db:
array(44) {
[0]=>
array(3) {
["id"]=>
string(2) "35"
["title"]=>
string(28) "ROOT1"
["path"]=>
string(28) "ROOT1"
}
[1]=>
array(3) {
["id"]=>
string(2) "36"
["title"]=>
string(27) "SUB_A"
["path"]=>
string(56) "ROOT1>SUB_A"
}
[2]=>
array(3) {
["id"]=>
string(2) "39"
["title"]=>
string(12) "SUB_A_1"
["path"]=>
string(69) "ROOT1>SUB_A>SUB_A_1"
}
[3]=>
array(3) {
["id"]=>
string(2) "37"
["title"]=>
string(28) "SUB_A_2"
["path"]=>
string(85) "ROOT1>SUB_A>SUB_A_2"
}
[4]=>
array(3) {
["id"]=>
string(2) "40"
["title"]=>
string(30) "SUB_A_3"
["path"]=>
string(87) "ROOT1>SUB_A>SUB_A_3"
}
[5]=>
array(3) {
["id"]=>
string(2) "43"
["title"]=>
string(19) "SUB_A_4"
["path"]=>
string(76) "ROOT1>SUB_A>SUB_A_4"
}
[6]=>
array(3) {
["id"]=>
string(2) "41"
["title"]=>
string(12) "SUB_A_5"
["path"]=>
string(69) "ROOT1>SUB_A>SUB_A_5"
}
[7]=>
array(3) {
["id"]=>
string(1) "1"
["title"]=>
string(20) "ROOT2"
["path"]=>
string(20) "ROOT2"
}
[8]=>
array(3) {
["id"]=>
string(2) "30"
["title"]=>
string(37) "ROOT3"
["path"]=>
string(37) "ROOT3"
}
[9]=>
array(3) {
["id"]=>
string(2) "34"
["title"]=>
string(21) "SUB_B"
["path"]=>
string(59) "ROOT3>SUB_B"
}
[10]=>
array(3) {
["id"]=>
string(2) "31"
["title"]=>
string(15) "SUB_C"
["path"]=>
string(53) "ROOT3>SUB_C"
}
I want to format values of path become structured array, here is what I try:
function format(array $data) : array
{
$single = [];
// format to single data
foreach ($data as $value) {
$single[] = $value['path'];
}
$result = [];
foreach ($single as $path) {
$parts = explode('>', $path);
$section = &$result;
$sectionName = '';
foreach ($parts as $part) {
$sectionName = $part;
if (array_key_exists($sectionName, $section) === FALSE) {
$section[$sectionName] = [];
}
$section = &$section[$sectionName];
}
}
return $result;
}
result:
array(3) {
["ROOT1"]=>
array(1) {
["SUB_A"]=>
array(5) {
["SUB_A_1"]=>
array(0) {
}
["SUB_A_2"]=>
array(0) {
}
["SUB_A_3"]=>
array(0) {
}
["SUB_A_4"]=>
array(0) {
}
["SUB_A_5"]=>
array(0) {
}
}
}
["ROOT2"]=>
array(0) {
}
["ROOT3"]=>
array(2) {
["SUB_B"]=>
array(0) {
}
["SUB_C"]=>
array(0) {
}
}
i need to include values of id and title to each path as expected result:
array(3) {
[0]=>
array(3) {
["title"]=>
string(5) "ROOT1"
["id"]=>
int(35)
["children"]=>
array(1) {
[0]=>
array(3) {
["title"]=>
string(5) "SUB_A"
["id"]=>
int(36)
["children"]=>
array(5) {
[0]=>
array(2) {
["title"]=>
string(7) "SUB_A_1"
["id"]=>
int(39)
}
[1]=>
array(2) {
["title"]=>
string(7) "SUB_A_2"
["id"]=>
int(37)
}
[2]=>
array(2) {
["title"]=>
string(7) "SUB_A_3"
["id"]=>
int(40)
}
[3]=>
array(2) {
["title"]=>
string(7) "SUB_A_4"
["id"]=>
int(43)
}
[4]=>
array(2) {
["title"]=>
string(7) "SUB_A_5"
["id"]=>
int(41)
}
}
}
}
}
[1]=>
array(2) {
["title"]=>
string(5) "ROOT2"
["id"]=>
int(1)
}
[2]=>
array(3) {
["title"]=>
string(5) "ROOT3"
["id"]=>
int(30)
["children"]=>
array(2) {
[0]=>
array(2) {
["title"]=>
string(5) "SUB_B"
["id"]=>
int(34)
}
[1]=>
array(2) {
["title"]=>
string(5) "SUB_C"
["id"]=>
int(31)
}
}
}
}
I would be grateful for any help you are able to provide.
Here's how I would do it. Test
I used arrow functions to reduce the amount of lines and there are inline comments to explain what I did.
<?php
$data = [["id"=> "35", "title"=> "ROOT1", "path"=> "ROOT1"], ["id"=> "36", "title"=> "SUB_A", "path"=> "ROOT1>SUB_A"], ["id"=> "37", "title"=> "SUB_A_1", "path"=> "ROOT1>SUB_A>SUB_A_1"], ["id"=> "38", "title"=> "SUB_A_2", "path"=> "ROOT1>SUB_A>SUB_A_2"], ["id"=> "39", "title"=> "SUB_A_3", "path"=> "ROOT1>SUB_A>SUB_A_3"], ["id"=> "40", "title"=> "SUB_A_4", "path"=> "ROOT1>SUB_A>SUB_A_4"], ["id"=> "41", "title"=> "SUB_A_5", "path"=> "ROOT1>SUB_A>SUB_A_5"], ["id"=> "1", "title"=> "ROOT2", "path"=> "ROOT2"], ["id"=> "30", "title"=> "ROOT3", "path"=> "ROOT3"], ["id"=> "34", "title"=> "SUB_B", "path"=> "ROOT3>SUB_B"], ["id"=> "31", "title"=> "SUB_C", "path"=> "ROOT3>SUB_C"]];
// The path is defaulted to an empty string, so the regex would return the highest level elements only because they don't have any `>`
function get_children($data, $path = '')
{
$results = array_values(array_filter($data, fn($item) => preg_match("/^{$path}[^>]+$/", $item['path'])));
// This regex, uses the passed path (e.g ROOT1) and searches for elements with anything but another `>`, because `>` signifies an inner directory.
// So this would return elements with a path like `ROOT1>SUB_A, ROOT1>SUB_B` but not `ROOT1>SUB_A>SUB_A_1`
foreach($results as $i => $result) {
// then I iterate through the result to get the element's children
$children = array_values(get_children($data, "{$result['path']}>"));
if (count($children)) $results[$i]['children'] = $children;
unset($results[$i]['path']); // Removing the path key from the array
}
return $results;
}
$format = fn($data) => get_children($data);
print_r($format($data));

Gwt data string from inside a nested array

I have an array with a lot of nested array data.
I need to get:
array(4) { ["id"]=> int(90)
this number, the 90.
Please see the whole array data below.
Thank you very much for help.
array(2)
{ ["_sft_product_cat"]=>array(5)
{
["name"]=> string(18)
"Produkt-Kategorien"
["singular_name"]=> string(9)
"Kategorie"
["all_items_label"]=> string(15)
"Alle Kategorien"
["type"]=> string(8)
"taxonomy"
["active_terms"]=> array(1)
{ [0]=> array(4)
{ ["id"]
=> int(90) ["name"]
=> string(7) "Hyundai" ["value"]
=> string(7) "hyundai" ["count"]
=> int(0)
}
}
}
["_sft_pa_typ"]=> array(5)
{ ["name"]
=> string(18) "Produkt Typ/Modell" ["singular_name"]
=> string(10) "Typ/Modell" ["all_items_label"]
=> string(5) "Al le " ["type"]
=> string(8) "taxonomy" ["active_terms"]
=> array(1)
{ [0]=> array(4)
{ ["id"]
=> int(9040) ["name"]
=> string(8) "Coupe GK" ["value"]
=> string(8) "coupe-gk" ["count"]=> int(0) } } } }
You're looking for:
$whatever_your_var_name_is["_sft_product_cat"]["active_terms"][0]["id"]
That is the same as referencing the levels one by one...
$sft_product_cat = $whatever_your_var_name_is['_sft_product_cat'];
$active_terms = $sft_product_cat['active_terms'];
$first_terms = $active_terms[0];
$id = $first_terms['id'];
It's notable that active_terms has a numeric indexed array (the [0] part). It's a hint that other instances of '_sft_product_cat' might have more than 1 terms and you'll need a loop to get them all.
I'm not familiar with php, but firstly I would format and indent the code to get a better picture of what you need from the nested objects:
array(2) {
["_sft_product_cat"]=> array(5)
{
["name"]=> string(18) "Produkt-Kategorien"
["singular_name"]=> string(9) "Kategorie"
["all_items_label"]=> string(15) "Alle Kategorien"
["type"]=> string(8) "taxonomy"
["active_terms"]=> array(1)
{
[0]=> array(4)
{
["id"]=> int(90)
["name"]=> string(7) "Hyundai"
["value"]=> string(7) "hyundai"
["count"]=> int(0)
}
}
}
["_sft_pa_typ"]=> array(5)
{
["name"]=> string(18) "Produkt Typ/Modell"
["singular_name"]=> string(10) "Typ/Modell"
["all_items_label"]=> string(5) "Alle "
["type"]=> string(8) "taxonomy"
["active_terms"]=> array(1)
{
[0]=> array(4)
{
["id"]=> int(9040) ["name"]=> string(8) "Coupe GK"
["value"]=> string(8) "coupe-gk" ["count"]=> int(0)
}
}
}
}
This would lead me to believe that you're after the id at:
<object>["_sft_product_cat"]["active_terms"][0]["id]
or
<object>[0][4][0][0]

combine same index of array?

I have following $_POST array
array(5) {
["addcatagory"]=>
string(8) "CATEGORY"
["reg_admin_id"]=>
string(2) "25"
["subcatagory"]=>
array(2) {
[0]=>
string(9) "SUB CAT 1"
[1]=>
string(9) "sub cat 2"
}
["subCat_Detais"]=>
array(2) {
[0]=>
string(9) "AAAAAAAAA"
[1]=>
string(8) "BBBBBBBB"
}
["submit"]=>
string(15) "Submit Catagory"
}
and
array(1) {
["subCatFile1"]=>
array(5) {
["name"]=>
array(3) {
[0]=>
string(5) "2.jpg"
[1]=>
string(5) "3.jpg"
[2]=>
string(0) ""
}
["type"]=>
array(3) {
[0]=>
string(10) "image/jpeg"
[1]=>
string(10) "image/jpeg"
[2]=>
string(0) ""
}
["tmp_name"]=>
array(3) {
[0]=>
string(18) "/var/tmp/phpN5ENy2"
[1]=>
string(18) "/var/tmp/phpRyJdcc"
[2]=>
string(0) ""
}
["error"]=>
array(3) {
[0]=>
int(0)
[1]=>
int(0)
[2]=>
int(4)
}
["size"]=>
array(3) {
[0]=>
int(65101)
[1]=>
int(49550)
[2]=>
int(0)
}
}
}
now what i want to achieve is combine 0 index of subcatagory and subcat_details in one array and of 1 index of subcatagory and subcat_details in second array and so on...
how can i achieve this?? is it even possible??
Expectations
array( 'name' => 'SUB CAT 1',
'details' => 'AAAAAAAAA',
'image_name'=>'2.jpg'
);
array( 'name' => 'SUB CAT 2',
'details' => 'BBBBBBB',
'image_name'=>'2.jpg'
);
This can be done with a simple foreach() loop -
$newArray = [];
foreach($_POST["subcatagory"] as $key => $value) {
$newArray[] = array("name" => $_POST["subcatagory"][$key],
"details" => $_POST["subCat_Detais"][$key]);
}
As #CharlotteDunois mentioned, you could also use an for() loop, as long as you have sequential keys, with no keys missing -
$newArray = [];
for($i=0;$i<count($_POST["subcatagory"]);$i++) {
$newArray[] = array("name" => $_POST["subcatagory"][$i],
"details" => $_POST["subCat_Detais"][$i]);
}

How to merge PHP multidimensional array keeping a unique key and separating with comma the other value

I have a multidimensional array and I want to make it matching the "unique key" value but merge the other key that has the same "unique key" value, it could be speared by comma, since my final output will be to use json_encode.
So for instance, if I have:
[0]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "123"
}
[1]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "124"
}
[2]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "126"
}
[3]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "129"
}
[4]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "130"
}
[5]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "102"
}
[6]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "193"
}
[7]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string(8) "156"
}
[8]=>
array(2) {
["label"]=>
string(2) "BG"
["value"]=>
string(8) "246"
}
[9]=>
array(2) {
["label"]=>
string(1) "C"
["value"]=>
string(8) "234"
}
[10]=>
array(2) {
["label"]=>
string(1) "C"
["value"]=>
string(8) "235"
}
[11]=>
array(2) {
["label"]=>
string(2) "CA"
["value"]=>
string(8) "345"
}
[12]=>
array(2) {
["label"]=>
string(2) "CA"
["value"]=>
string(8) "564"
}
And I want an output like:
[0]=>
array(2) {
["label"]=>
string(2) "AB"
["value"]=>
string "123,124,126,129,130,102,193,156“
}
[1]=>
array(2) {
["label"]=>
string(2) "BG"
["value"]=>
string "246"
}
[2]=>
array(2) {
["label"]=>
string(1) "C"
["value"]=>
string(8) "234,235,”
}
[3]=>
array(2) {
["label"]=>
string(2) "CA"
["value"]=>
string(8) "345,564,”
}
I am not sure how to do it, I've looked into array_merge_recursive and other similar solutions, but I did not got it, maybe I need to use implode.
You can use something like this:
$result = array();
foreach ($array as $arr) {
if (!isset($result[$arr['label']])) {
$result[$arr['label']] = $arr;
continue;
}
$result[$arr['label']]['value'] .= ',' . $arr['value'];
}
// if you really need numeric indexes use:
$result = array_values($result);
You can try
$array = array(
array(
'label' => "AB",
'value' => 123
),
array(
'label' => "AB",
'value' => 124
),
array(
'label' => "AB",
'value' => 125
),
array(
'label' => "C",
'value' => 126
),
array(
'label' => "C",
'value' => 127
),
array(
'label' => "C",
'value' => 127
),
);
$result = array();
foreach ($array as $el) {
$result[$el['label']] = array(
'label' => $el['label'],
'value' => implode( ',',
array_unique(
array_merge(
array_filter(
explode(',', $result[$el['label']]['value'])
),
array($el['value'])
)
)
)
);
}
echo "<pre>"; var_dump(array_values($result));

getting a unique values from array

I currently have an array that looks like the one below but I only want to display show results in the array from which are unique (description), I presume with array_unique? but I keep getting the same results?
Here is my array:
$taglist = array(5) {
[0]=> array(5) {
["id"]=> string(2) "27"
["page_id"]=> string(2) "18"
["description"]=> string(10) "Web Design"
["slug"]=> string(10) "web-design"
["visibility"]=> string(7) "visible"
}
[1]=> array(5) {
["id"]=> string(2) "29"
["page_id"]=> string(2) "18"
["description"]=> string(3) "Tutorials"
["slug"]=> string(3) "tutorials"
["visibility"]=> string(7) "visible"
}
[2]=> array(5) {
["id"]=> string(2) "31"
["page_id"]=> string(2) "21"
["description"]=> string(3) "tag"
["slug"]=> string(3) "tag"
["visibility"]=> string(7) "visible"
}
[3]=> array(5) {
["id"]=> string(2) "32"
["page_id"]=> string(2) "21"
["description"]=> string(10) "Web Design"
["slug"]=> string(10) "web-design"
["visibility"]=> string(7) "visible"
}
}
Here is my while:
$items = array();
$results = $taglist;
foreach ($results as $result)
{
$items[]= $result['description'];
$items = array_unique($items);
}
echo '<ul>';
while ($tag_item = current($items))
{
echo '<li>'.$tag_item['description'].'</li>';
next($items);
}
echo '</ul>';
$taglist = array(
0 => array('description'=>'one'),
1 => array('description'=>'two'),
2 => array('description'=>'one'),
3 => array('description'=>'three'),
4 => array('description'=>'one'),
);
// echo var_export($taglist, 1); // uncomment to see the diff vs var_dump()
foreach($taglist as $tag){
$new[] = $tag['description'];
}
var_dump(array_unique($new));

Categories