Regex to extract multiple substrings from strings with a predictable format - php

I got this string below.
string(49) "02/12/2018 (Assessment 2) = /86= | Weight: 50.00%"
string(49) "02/12/2018 (Assessment 2) = 50.83/86= | Weight: 50.00%""
The first example don't show any number before the /, in this case I need to use 00.00 as the default value.
I need to get this information and put in an array like this one:
$dados[ "date" ] = "02/12/2018"
$dados[ "markOK" ] = "50"
$dados[ "markTotal" ] = "86"
$dados[ "weight" ] = "50.00"
Other examples:
string(49) "02/12/2018 (Assessment 2) = /86= | Weight: 50.00%"
string(59) "06/11/2018 (Assessment 2) = 22.40/35=32.00 | Weight: 50.00%"
string(49) "04/12/2018 (Assessment 2) = /60= | Weight: 50.00%"
string(59) "11/09/2018 (Assessment 2) = 27.00/40=33.75 | Weight: 50.00%"
string(59) "09/09/2018 (Assessment 2) = 30.00/30=50.00 | Weight: 50.00%"
string(59) "14/08/2018 (Assessment 2) = 31.00/40=38.75 | Weight: 50.00%"
string(59) "19/06/2018 (Assessment 2) = 63.00/72=43.75 | Weight: 50.00%"
string(59) "17/06/2018 (Assessment 2) = 45.00/45=50.00 | Weight: 50.00%"
string(59) "22/05/2018 (Assessment 2) = 11.00/55=10.00 | Weight: 50.00%"

Like this:
(?P<date>\d{2}\/\d{2}\/\d{4})[^=]+=\s(?P<markOK>\d+(?:\.\d+)?)?\/(?P<markTotal>\d+)[^:]+:\s(?P<weight>\d+(?:\.\d+)?)
Test online
It's actually pretty simple.
(?P<date>\d{2}\/\d{2}\/\d{4}) capture the date
[^=]+=\s skip everything not an equal then the equal and a space
(?P<markOK>\d+(?:\.\d+)?)? capture float (optional)
\/ the slash
(?P<markTotal>\d+) capture integer
[^:]+:\s skip everything not a colon then the colon and a space
(?P<weight>\d+(?:\.\d+)?) capture float
Update
$pattern = '/(?P<date>\d{2}\/\d{2}\/\d{4})[^=]+=\s(?P<markOK>\d+(?:\.\d+)?)?\/(?P<markTotal>\d+)[^:]+:\s(?P<weight>\d+(?:\.\d+)?)/';
if(preg_match($pattern, $str, $matches)){
var_export($matches);
}
If you want to clean up the matches array you can do it like this:
$str = '04/12/2018 (Assessment 2) = /60= | Weight: 50.00%';
$pattern = '/(?P<date>\d{2}\/\d{2}\/\d{4})[^=]+=\s(?P<markOK>\d+(?:\.\d+)?)?\/(?P<markTotal>\d+)[^:]+:\s(?P<weight>\d+(?:\.\d+)?)/';
if(preg_match($pattern, $str, $matches)){
$default = [
'date' => '00/00/0000',
'markOK' => '0.00',
'markTotal' => '0',
'weight' => '0.00'
];
$matches = array_filter($matches);
$matches = array_merge($default, array_intersect_key($matches, $default));
var_export($matches);
}
Try it online
Output
array (
'date' => '04/12/2018',
'markOK' => '0.00',
'markTotal' => '60',
'weight' => '50.00',
)

While using named capture groups certainly has purpose for this case, I find the syntax makes the pattern unnecessarily bloated and harder to read. After matching the substrings (notably the optional 2nd substring), you'll need to write a condition to replace the zero-length string with 00.00.
Here's what I recommend:
Code: (PHP Demo) (Regex Demo)
$strings = [
"02/12/2018 (Assessment 2) = /86= | Weight: 50.00%",
"06/11/2018 (Assessment 2) = 22.40/35=32.00 | Weight: 50.00%",
"04/12/2018 (Assessment 2) = /60= | Weight: 50.00%",
"11/09/2018 (Assessment 2) = 27.00/40=33.75 | Weight: 50.00%",
"09/09/2018 (Assessment 2) = 30.00/30=50.00 | Weight: 50.00%",
"14/08/2018 (Assessment 2) = 31.00/40=38.75 | Weight: 50.00%",
"19/06/2018 (Assessment 2) = 63.00/72=43.75 | Weight: 50.00%",
"17/06/2018 (Assessment 2) = 45.00/45=50.00 | Weight: 50.00%",
"22/05/2018 (Assessment 2) = 11.00/55=10.00 | Weight: 50.00%"
];
foreach ($strings as $string) {
if (!preg_match('~(\d\d/\d\d/\d{4})[^=]+= (\d+(?:\.\d+)?)?/(\d+)[^:]+: (\d+(?:\.\d+)?)~', $string, $m)) {
echo "No match for string: $string\n";
} else {
$results[] = ['date' => $m[1], 'markOK' => strlen($m[2]) ? $m[2] : '00.00', 'markTotal' => $m[3], 'weight' => $m[4]];
}
}
var_export($results);
Output:
array (
0 =>
array (
'date' => '02/12/2018',
'markOK' => '00.00',
'markTotal' => '86',
'weight' => '50.00',
),
1 =>
array (
'date' => '06/11/2018',
'markOK' => '22.40',
'markTotal' => '35',
'weight' => '50.00',
),
2 =>
array (
'date' => '04/12/2018',
'markOK' => '00.00',
'markTotal' => '60',
'weight' => '50.00',
),
3 =>
array (
'date' => '11/09/2018',
'markOK' => '27.00',
'markTotal' => '40',
'weight' => '50.00',
),
4 =>
array (
'date' => '09/09/2018',
'markOK' => '30.00',
'markTotal' => '30',
'weight' => '50.00',
),
5 =>
array (
'date' => '14/08/2018',
'markOK' => '31.00',
'markTotal' => '40',
'weight' => '50.00',
),
6 =>
array (
'date' => '19/06/2018',
'markOK' => '63.00',
'markTotal' => '72',
'weight' => '50.00',
),
7 =>
array (
'date' => '17/06/2018',
'markOK' => '45.00',
'markTotal' => '45',
'weight' => '50.00',
),
8 =>
array (
'date' => '22/05/2018',
'markOK' => '11.00',
'markTotal' => '55',
'weight' => '50.00',
),
)

Related

How to export a multi dimensional array to a specific .csv layout with fputcsv PHP

I know the answer to this will be obvious but I have spent the last 3 days trying to figure it out. I am having trouble getting a Multi-Dimensional array to export into the correct layout in the exported .csv file.
I seem to able to either get all the data but not in the correct layout or I can get the correct layout but not all the data.
This is the array
array (size=106)
0 =>
array (size=6)
0 => string 'Title' (length=5)
1 => string 'image_url' (length=9)
3 => string 'SKU CODE' (length=8)
4 => string 'TITLE SIZE' (length=10)
5 => string 'DESCRIPTION' (length=11)
6 => string 'BASE SKU' (length=8)
1 =>
array (size=6)
0 => string 'A witch and her cat live here' (length=29)
1 => string 'https://beautifulhomegifts.com/a-witch-and-her-cat-live-here/' (length=61)
3 =>
array (size=4)
0 => string 'BHG-MS-AWAHCLH030720' (length=20)
1 => string 'BHG-MS-AWAHCLH030720-A5' (length=23)
2 => string 'BHG-MS-AWAHCLH030720-A4' (length=23)
3 => string 'BHG-MS-AWAHCLH030720-A3' (length=23)
4 =>
array (size=4)
0 => string 'A witch and her cat live here' (length=29)
1 => string 'A witch and her cat live here - 150mm x 200mm' (length=45)
2 => string 'A witch and her cat live here - 201mm x 305mm' (length=45)
3 => string 'A witch and her cat live here - 305mm x 400mm' (length=45)
5 =>
array (size=4)
0 => string 'A witch and her cat live here' (length=29)
1 => string 'A witch and her cat live here' (length=29)
2 => string 'A witch and her cat live here' (length=29)
3 => string 'A witch and her cat live here' (length=29)
6 =>
array (size=3)
1 => string 'BHG-MS-AWAHCLH030720' (length=20)
2 => string 'BHG-MS-AWAHCLH030720' (length=20)
3 => string 'BHG-MS-AWAHCLH030720' (length=20)
2 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
3 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
4 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
5 =>
array (size=6)
0 => string 'Autism House Rules' (length=18)
1 => string 'https://beautifulhomegifts.com/autism-house-rules/' (length=50)
3 =>
array (size=4)
0 => string 'BHG-MS-AHR030720' (length=16)
1 => string 'BHG-MS-AHR030720-A5' (length=19)
2 => string 'BHG-MS-AHR030720-A4' (length=19)
3 => string 'BHG-MS-AHR030720-A3' (length=19)
4 =>
array (size=4)
0 => string 'Autism House Rules' (length=18)
1 => string 'Autism House Rules - 150mm x 200mm' (length=34)
2 => string 'Autism House Rules - 201mm x 305mm' (length=34)
3 => string 'Autism House Rules - 305mm x 400mm' (length=34)
5 =>
array (size=4)
0 => string 'Autism House Rules' (length=18)
1 => string 'Autism House Rules' (length=18)
2 => string 'Autism House Rules' (length=18)
3 => string 'Autism House Rules' (length=18)
6 =>
array (size=3)
1 => string 'BHG-MS-AHR030720' (length=16)
2 => string 'BHG-MS-AHR030720' (length=16)
3 => string 'BHG-MS-AHR030720' (length=16)
6 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
7 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
8 =>
array (size=2)
0 => string '' (length=0)
1 => string '' (length=0)
9 =>
I have tried multiple ways to get this to work and this is the closest I have got to it being correct
$f = fopen('new.csv', 'a'); // Configure fOpen to create, open and write only.
if ($f != false){
// Loop over the array and passing in the values only.
foreach ($the_big_array as $row){
fputcsv($f, $row);
}
}
fclose($f);
This gives me this layout but it just shows there is a child array and does not output the data of the child arrays.
Above is the output I am getting.
Below is the layout I want to achieve.
I have also tried a foreach loop inside a foreach loop to get the data, when I do this I get all the data but not in the same layout. I have looked through all the posts on here and so many get close to what I want to achieve but none of them give the correct layout.
To summarise, I want to export $the_big_array to a .csv file that has the layout of the second image of a .csv in a spreadsheet. Thank you
array (
0 =>
array (
0 => 'Title',
1 => 'image_url',
3 => 'SKU CODE',
4 => 'TITLE SIZE',
5 => 'DESCRIPTION',
6 => 'BASE SKU',
),
1 =>
array (
0 => 'A witch and her cat live here',
1 => 'https://beautifulhomegifts.com/a-witch-and-her-cat-live-here/',
3 =>
array (
0 => 'BHG-MS-AWAHCLH030720',
1 => 'BHG-MS-AWAHCLH030720-A5',
2 => 'BHG-MS-AWAHCLH030720-A4',
3 => 'BHG-MS-AWAHCLH030720-A3',
),
4 =>
array (
0 => 'A witch and her cat live here',
1 => 'A witch and her cat live here - 150mm x 200mm',
2 => 'A witch and her cat live here - 201mm x 305mm',
3 => 'A witch and her cat live here - 305mm x 400mm',
),
5 =>
array (
0 => 'A witch and her cat live here',
1 => 'A witch and her cat live here',
2 => 'A witch and her cat live here',
3 => 'A witch and her cat live here',
),
6 =>
array (
1 => 'BHG-MS-AWAHCLH030720',
2 => 'BHG-MS-AWAHCLH030720',
3 => 'BHG-MS-AWAHCLH030720',
),
),
2 =>
array (
0 => '',
1 => '',
),
3 =>
array (
0 => '',
1 => '',
),
4 =>
array (
0 => '',
1 => '',
),
5 =>
array (
0 => 'Autism House Rules',
1 => 'https://beautifulhomegifts.com/autism-house-rules/',
3 =>
array (
0 => 'BHG-MS-AHR030720',
1 => 'BHG-MS-AHR030720-A5',
2 => 'BHG-MS-AHR030720-A4',
3 => 'BHG-MS-AHR030720-A3',
),
4 =>
array (
0 => 'Autism House Rules',
1 => 'Autism House Rules - 150mm x 200mm',
2 => 'Autism House Rules - 201mm x 305mm',
3 => 'Autism House Rules - 305mm x 400mm',
),
5 =>
array (
0 => 'Autism House Rules',
1 => 'Autism House Rules',
2 => 'Autism House Rules',
3 => 'Autism House Rules',
),
6 =>
array (
1 => 'BHG-MS-AHR030720',
2 => 'BHG-MS-AHR030720',
3 => 'BHG-MS-AHR030720',
),
),
Ok since the array is malformed and the code is a bit lengthy, I would like to say that we
First, print the headers by popping the first entry in the array.
Make each row have same number of entries by getting the max depth/ max count that a row entry could go with entry values.
Print each new row which is symmetrically arranged by using array_column(). You can print $final_row_data in the code to get a better view of how it is symmeterically arranged.
Snippet:
<?php
$the_big_array = array (
0 =>
array (
0 => 'Title',
1 => 'image_url',
3 => 'SKU CODE',
4 => 'TITLE SIZE',
5 => 'DESCRIPTION',
6 => 'BASE SKU',
),
1 =>
array (
0 => 'A witch and her cat live here',
1 => 'https://beautifulhomegifts.com/a-witch-and-her-cat-live-here/',
3 =>
array (
0 => 'BHG-MS-AWAHCLH030720',
1 => 'BHG-MS-AWAHCLH030720-A5',
2 => 'BHG-MS-AWAHCLH030720-A4',
3 => 'BHG-MS-AWAHCLH030720-A3',
),
4 =>
array (
0 => 'A witch and her cat live here',
1 => 'A witch and her cat live here - 150mm x 200mm',
2 => 'A witch and her cat live here - 201mm x 305mm',
3 => 'A witch and her cat live here - 305mm x 400mm',
),
5 =>
array (
0 => 'A witch and her cat live here',
1 => 'A witch and her cat live here',
2 => 'A witch and her cat live here',
3 => 'A witch and her cat live here',
),
6 =>
array (
1 => 'BHG-MS-AWAHCLH030720',
2 => 'BHG-MS-AWAHCLH030720',
3 => 'BHG-MS-AWAHCLH030720',
),
),
2 =>
array (
0 => '',
1 => '',
),
3 =>
array (
0 => '',
1 => '',
),
4 =>
array (
0 => '',
1 => '',
),
5 =>
array (
0 => 'Autism House Rules',
1 => 'https://beautifulhomegifts.com/autism-house-rules/',
3 =>
array (
0 => 'BHG-MS-AHR030720',
1 => 'BHG-MS-AHR030720-A5',
2 => 'BHG-MS-AHR030720-A4',
3 => 'BHG-MS-AHR030720-A3',
),
4 =>
array (
0 => 'Autism House Rules',
1 => 'Autism House Rules - 150mm x 200mm',
2 => 'Autism House Rules - 201mm x 305mm',
3 => 'Autism House Rules - 305mm x 400mm',
),
5 =>
array (
0 => 'Autism House Rules',
1 => 'Autism House Rules',
2 => 'Autism House Rules',
3 => 'Autism House Rules',
),
6 =>
array (
1 => 'BHG-MS-AHR030720',
2 => 'BHG-MS-AHR030720',
3 => 'BHG-MS-AHR030720',
),
)
);
$headers = array_shift($the_big_array);
$header_keys = array_keys($headers);
$fhandle = fopen("sample.csv","a+");// have w+ if you want to override each time.
fputcsv($fhandle,$headers);// add headers first
foreach($the_big_array as $row_data){
$insert_row = [];
// making consistent with all header keys
foreach($header_keys as $key){
if(isset($row_data[$key])){
$insert_row[$key] = $row_data[$key];
}else{
$insert_row[$key] = '';
}
}
if(count(array_filter($insert_row)) == 0) continue;
$final_row_data = [];
$max_depth_size = 0;
foreach($insert_row as $value){
if(is_array($value)){
$max_depth_size = max($max_depth_size,count($value));
}
}
foreach($insert_row as $key => $value){
$temp = [];
if(is_array($value)){
$value = array_values($value); // since data is malformed(would work even if it is ok)
$val_size = count($value);
for($i = 0; $i < $max_depth_size; ++$i){
if($i >= $val_size) $temp[$i] = '';
else $temp[$i] = $value[$i];
}
}else{
$temp = array_merge(array($value),array_fill(0, $max_depth_size - 1, ''));
}
$final_row_data[] = $temp;
}
for($column = 0;$column < $max_depth_size; ++$column){
fputcsv($fhandle,array_column($final_row_data, $column)); // add all formatted data to CSV
}
}
fclose($fhandle);
Your starting array is bad-formed, because it is not consistent in the dimensions of the child array and in the indexes. That's a valid solution, but it's very fragile because there are a lot of assumption about the array structure.
$f = fopen('new.csv', 'a');
// Write the header
fputcsv($f, array_values(array_shift($the_big_array)));
foreach($the_big_array as $baseRow) {
if (empty($baseRow[0]) continue
$subRowsCount = count($baseRow[3])
if (
count($baseRow[4]) !== $subRowsCount
|| count($baseRow[5]) !== $subRowsCount
|| count($baseRow[6]) !== $subRowsCount - 1)
} {
// Check that the sub-arrays dimensions are consistent or ignore the row
continue;
}
for($i = 0; $i < $subRowsCount; $i++) {
fputcsv($f, [
$i === 0 ? $baseRow[0] : '', // Title
$i === 0 ? $baseRow[1] : '', // image_url
$baseRow[3][$i], // SKU code
$baseRow[4][$i], // Title size
$baseRow[5][$i], // Description
$i === 0 ? '' : $baseRow[6][$i-1] // Base sku
])
}
}
The first row of each "group" contains the max number of columns so it can be used to reliably fetch column data.
Tear off the title and url values as you iterate your input array so that the remaining data in the subarray has a consistent and easily manipulated structure.
Rows that have missing trailing columns do not matter when pushing csv rows into a file, so it is a waste of code to bother generating empty strings. Conversely, leading empty column values will be a problem -- this is why I add two empty strings when not adding the first row of a respective group.
Read the PSR coding standards to see recommendations on spacing and curly brace usage.
Code: (Demo)
$headers = array_shift($array);
$fhandle = fopen("new.csv", "a");
fputcsv($fhandle, $headers);
foreach ($array as $row) {
if (empty($row[0])) {
continue;
}
$titleAndUrl = array_splice($row, 0, 2);
foreach ($row[0] as $column => $notUsed) {
fputcsv(
$fhandle,
array_merge(
!$column ? $titleAndUrl : ['', ''],
array_column($row, $column)
)
);
}
}
fclose($fhandle);
See demo for output in array form.

Laravel Eloquent Nested Group by its Relation

Please help me how to add another nested group by based on game category relation. I have 3 tables related using laravel 5.4 eloquent.
Game Providers Table
+----+-------------+--------------+------------------+
| id | game_name | game_type_id | game_category_id |
+----+-------------+--------------+------------------+
| 1 | Sample | 1 | 1 |
| 1 | Sample 0 | 1 | 2 |
| 2 | Sample 1 | 2 | 1 |
| 3 | Sample 2 | 2 | 2 |
+----+-------------+--------------+------------------+
Game Types
+----+-------------+
| id | name |
+----+-------------+
| 1 | Chess |
| 2 | Poker |
+----+-------------+
Game Categories
+----+-------------+
| id | name |
+----+-------------+
| 1 | Recommended |
| 2 | Optional |
+----+-------------+
I'm done of for first nested for game type relation but i dont know how to add another group by for game categories
$game_providers = GameProvider::all();
$game_providers = $game_providers->groupBy(function ($game_provider) {
return $game_provider->game_type->name;
})->all();
and its output
Array{
'Chess' => Array{
0 => Array{
'id' => 1,
'game_name' => 'Sample',
'game_type_id' => 1,
'game_category_id' => 2
},
1 => Array{
'id' => 2,
'game_name' => 'Sample 0',
'game_type_id' => 1,
'game_category_id' => 2
},
},
'Poker' => Array{
0 => Array{
'id' => 3,
'game_name' => 'Sample 1',
'game_type_id' => 2,
'game_category_id' => 1
},
1 => Array{
'id' => 4,
'game_name' => 'Sample 2',
'game_type_id' => 2,
'game_category_id' => 2
},
},
}
My expected output
Array{
'Chess' => Array{
'Recommended' => Array{
0 => Array{
'id' => 1,
'game_name' => 'Sample',
'game_type_id' => 1,
'game_category_id' => 2
}
},
'Optional' => Array{
0 => Array{
'id' => 2,
'game_name' => 'Sample 0',
'game_type_id' => 1,
'game_category_id' => 2
}
}
},
'Poker' => Array{
'Recommended' => Array{
0 => Array{
'id' => 3,
'game_name' => 'Sample 1',
'game_type_id' => 2,
'game_category_id' => 1
}
},
'Optional' => Array{
0 => Array{
'id' => 4,
'game_name' => 'Sample 2',
'game_type_id' => 2,
'game_category_id' => 2
}
}
}
}
With L5, one way of acieving this can be:
GameProvider::with('game_categories.game_types')
->get()
->groupBy([
'gameTypes.name',
'gameCategories.name'
]);
Should be something along the lines of :
GameProvider::with('game_categories.game_types')->get()->map(function ($game) {
return $game->game_categories->groupBy('name')->map(function ($catGame) {
return $catGame->map(function ($category) {
return $category->game_types->groupBy('name');
});
});
});

Combine strings in multidimensional array and keep key - PHP [duplicate]

This question already has answers here:
How to implode an array to new lines [duplicate]
(2 answers)
Closed 10 months ago.
I have this array:
array(1) {
["comments"]=>
array(244) {
[113]=>
array(2) {
[0]=>
string(40) "2016-07-15 09:27 | From On Track to Done"
[1]=>
string(40) "2016-07-15 09:56 | From Done to On Track"
}
}
}
And I want to make into this array:
array(1) {
["comments"]=>
array(244) {
[113]=>
array(1) {
[0]=>
string(80) "2016-07-15 09:27 | From On Track to Done
2016-07-15 09:56 | From Done to On Track"
}
}
}
I need to keep the key [113] and merge the values.
I need all the comments to be in only one array.
In this example there are only two comments, but actually it is much more.
I tried with array_merge, array_value and a loop. I couldnt get it.
A more general algorithm would be :
<?php
// SAMPLE DATA.
$arr = array( "comments" => array( 0 => array( "2016-07-15 09:27 | From On Track to Done",
"2016-07-15 09:56 | From Done to On Track"
),
1 => array( "111 | aaa",
"222 | bbb",
"333 | ccc"
)
),
"posts" => array( 0 => array( "2016-07-13 08:00 | bla bla bla",
"2016-07-13 08:30 | more bla bla bla"
),
1 => array( "444 | xxx",
"555 | yyy",
"666 | zzz"
)
)
);
var_dump( $arr ); // ORIGINAL ARRAY.
$new = array();
foreach ( $arr as $key => $category ) // "COMMENTS", "POSTS", ...
{ for ( $i = 0; $i < count( $category ); $i++ ) // 0, 1, ...
{ $values = implode( $category[ $i ]," " ); // MERGE STRINGS.
$new[ $key ][ $i ] = array( $values );//WE CAN REMOVE "ARRAY" AND LEAVE ONLY "$VALUES".
}
}
var_dump( $new ); // NEW ARRAY.
?>
Result :
original array
array (size=2)
'comments' =>
array (size=2)
0 =>
array (size=2)
0 => string '2016-07-15 09:27 | From On Track to Done' (length=40)
1 => string '2016-07-15 09:56 | From Done to On Track' (length=40)
1 =>
array (size=3)
0 => string '111 | aaa' (length=9)
1 => string '222 | bbb' (length=9)
2 => string '333 | ccc' (length=9)
'posts' =>
array (size=2)
0 =>
array (size=2)
0 => string '2016-07-13 08:00 | bla bla bla' (length=30)
1 => string '2016-07-13 08:30 | more bla bla bla' (length=35)
1 =>
array (size=3)
0 => string '444 | xxx' (length=9)
1 => string '555 | yyy' (length=9)
2 => string '666 | zzz' (length=9)
new array
array (size=2)
'comments' =>
array (size=2)
0 =>
array (size=1)
0 => string '2016-07-15 09:27 | From On Track to Done 2016-07-15 09:56 | From Done to On Track' (length=81)
1 =>
array (size=1)
0 => string '111 | aaa 222 | bbb 333 | ccc' (length=29)
'posts' =>
array (size=2)
0 =>
array (size=1)
0 => string '2016-07-13 08:00 | bla bla bla 2016-07-13 08:30 | more bla bla bla' (length=66)
1 =>
array (size=1)
0 => string '444 | xxx 555 | yyy 666 | zzz' (length=29)
Try this:
$array['comments'][113] = implode(' ', $array['comments'][113]);
I don't know what is your array structure, but simple solution is:
$vals = implode("\n", $ar['comments'][113]);
$ar['comments'][113] = array();
$ar['comments'][113][] = $vals;
Or simpler:
$ar['comments'][113] = array(implode("\n", $ar['comments'][113]));
Thank you for the help! You were right. It was with implode.
The answer was this:
foreach ($goals["comments"] as $key => $value) {
$goals['comments'][$key][0] = implode($value, "\n");
}

How to build a "child-parent" tree/nested array from database?

TABLE `people`
+----+------------+-------+
| sn | name | upper |
+----+------------+-------+
| 1 | Clement | 0 |
| 2 | Jean | 1 |
| 3 | Annie | 1 |
| 4 | Yuan | 2 |
| 5 | Mei | 2 |
| 6 | Blue | 3 |
| 7 | Yang | 5 |
| 8 | Lorinda | 0 |
+----+------------+-------+
The structure is like:
Clement
Jean
Yuan
Mei
Yang
Annie
Blue
Lorinda
The column upper states the upper person of himself/herself.
The problem is: How can I get a nested/multi-dimensional array from MySQL?
I thought I could use loops to fetch, but I failed to automated fetch all the lowers.
The array could be like this:
Array
(
[1]=>Array
(
[self]=>Clement
[2]=>Array
(
[self]=>Jean
[4]=>Array
(
[self]=>Yuan
)
[5]=>Array
(
[self]=>Mei
[7]=>Array
(
[self]=>Yang
)
)
)
[3]=>Array
(
[self]=>Annie
[6]=>Array
(
[self]=>Blue
)
)
)
[8]=>Array
(
[self]=>Lorinda
)
)
Since we don't know how many 'upper' persons does one have, the solution should be an automated function that build a complete array, not just for three or four dimension.
In other word, the function should deep into all the lower person from a top person.
Given your input as:
$input = array(
array('sn' => 1, 'name' => 'Clement', 'upper' => 0),
array('sn' => 2, 'name' => 'Jean', 'upper' => 1),
array('sn' => 3, 'name' => 'Annie', 'upper' => 1),
array('sn' => 4, 'name' => 'Yuan', 'upper' => 2),
array('sn' => 5, 'name' => 'Mei', 'upper' => 2),
array('sn' => 6, 'name' => 'Blue', 'upper' => 3),
array('sn' => 7, 'name' => 'Yang', 'upper' => 5),
array('sn' => 8, 'name' => 'Lorinda', 'upper' => 0),
);
using references you can build a tree with the following loop:
$map = array();
foreach ($input as $node) {
// init self
if (!array_key_exists($node['sn'], $map)) {
$map[$node['sn']] = array('self' => $node['name']);
}
else {
$map[$node['sn']]['self'] = $node['name'];
}
// init parent
if (!array_key_exists($node['upper'], $map)) {
$map[$node['upper']] = array();
}
// add to parent
$map[$node['upper']][$node['sn']] = & $map[$node['sn']];
}
print_r($map[0]);
demo: http://3v4l.org/vuVPu
Assuming the data is like this
$data = array(
array(1, 'Clement', 0),
array(2, 'Jean ', 1),
array(3, 'Annie ', 1),
array(4, 'Yuan ', 2),
array(5, 'Mei ', 2),
array(6, 'Blue ', 3),
array(7, 'Yang ', 5),
array(8, 'Lorinda', 0),
);
this recursive function might work:
function tree($data, $node) {
foreach($data as $e)
if($e[2] == $node[0])
$node['children'] []= tree($data, $e);
return $node;
}
Use it like this:
$tree = tree($data, array(0));
print_r($tree);
using a reference map
$input = array(
array('sn' => 1, 'name' => 'Clement', 'upper' => 0),
array('sn' => 2, 'name' => 'Jean', 'upper' => 1),
array('sn' => 3, 'name' => 'Annie', 'upper' => 1),
array('sn' => 4, 'name' => 'Yuan', 'upper' => 2),
array('sn' => 5, 'name' => 'Mei', 'upper' => 2),
array('sn' => 6, 'name' => 'Blue', 'upper' => 3),
array('sn' => 7, 'name' => 'Yang', 'upper' => 5),
array('sn' => 8, 'name' => 'Lorinda', 'upper' => 0),
);
$map = []; // map a reference by id for each item
foreach ($input as &$inp) {
$map[$inp['sn']] = &$inp;
}
foreach ($map as &$_inp) { // assign each item to its parent, with help of the map
if ($_inp['upper']) {
$map[$_inp['upper']]['children'] = &$map[$_inp['upper']]['children'] ?? [];
$map[$_inp['upper']]['children'][] = &$_inp;
}
}
$result = array_filter($map, fn($item) => !$item['upper']);
print_r($result);```

sort multilevel array php

I have the following array:
array(
array(
id: 4,
name: car,
pid: 0
),
array(
id: 5,
name: lights,
pid: 4
),
array(
id: 6,
name: fog,
pid: 5
)
),
array(
array(
id: 1,
name: bike,
pid: 0
),
array(
id: 2,
name: wheel,
pid: 1
),
array(
id: 3,
name: tire,
pid: 2
)
),
array(
id: 7,
name: car,
pid: 0
),
array(
id: 8,
name: lights,
pid: 7
),
array(
id: 9,
name: brake,
pid: 8
)
),
array(
id: 10,
name: car,
pid: 0
),
array(
id: 11,
name: engine,
pid: 10
)
),
)
These multidimesnional array represent the specifications of a car. In a table, it looks like:
| car -> lights -> fog |
| bike -> wheel -> tire |
| car -> lights -> brake |
| car -> engine |
And now I would like to sort the array, for each level on name. So first, sort on the first column, than sort on the second column etc...
Our sorted array should look like:
| bike -> wheel -> tire |
| car -> engine |
| car -> lights -> brake |
| car -> lights -> fog |
Using usort I can sort on the first column:
usort($characteristics, function($a, $b){
return $a[0]['name'] > $b[0]['name'];
});
But offcourse this only affects the first column and in this case, the array looks like:
| bike -> wheel -> tire |
| car -> lights -> fog |
| car -> lights -> brake |
| car -> engine |
It is also possible to have different lengths (like the engine, that has 2 values, and the bike, which has 3). Normally the length varies between 1 and 5.
I rather wouldn't use too much for/foreach loops, because that would slow my program too much. Also sorry for the long question, but I couldn't find a shorter way to explain my problem.
I hope someone can give me e simple clean solution.
I believe this is what you are looking for:
$arr =
array(
array(
array(
"id" => 4,
"name" => "car",
"pid" => 0
),
array(
"id" => 5,
"name" => "lights",
"pid" => 4
),
array(
"id" => 6,
"name" => "fog",
"pid" => 5
)
),
array(
array(
"id" => 1,
"name" => "bike",
"pid" => 0
),
array(
"id" => 2,
"name" => "wheel",
"pid" => 1
),
array(
"id" => 3,
"name" => "tire",
"pid" => 2
)
),
array(
array(
"id" => 7,
"name" => "car",
"pid" => 0
),
array(
"id" => 8,
"name" => "lights",
"pid" => 7
),
array(
"id" => 9,
"name" => "brake",
"pid" => 8
)
),
array(
array(
"id" => 10,
"name" => "car",
"pid" => 0
),
array(
"id" => 11,
"name" => "engine",
"pid" => 10
)
)
);
for ($i = 0; $i < count($arr); $i++) {
foreach ($arr[$i] as $a) {
foreach($a as $key => $value) {
if ($key == 'name') {
$newArr[$i][] = $value;
}
}
}
}
usort($newArr, function($a, $b) {
return $a[0] > $b[0];
});
echo "<pre>", print_r($newArr), "</pre>";

Categories