Multi-array idea php - php

I have a PHP array thats like this:
$a1 = [
[ 'buyer'=>"ACME", 'fees1'=>"100", 'seller'=>"XYZ plc", 'fees2'=>"200", 'item'=>"Bricks" ],
[ 'buyer'=>"ACME", 'fees1'=>"110", 'seller'=>"XYZ plc", 'fees2'=>"220", 'item'=>"Bricks" ],
[ 'buyer'=>"XYZ Plc", 'fees1'=>"200", 'seller'=>"ACME", 'fees2'=>"300", 'item'=>"Cement" ],
/* and so on and on */
];
So the report I am trying to produce is this:
BRICKS---CEMENT
ACME----220------300
XYZ-----440------200
--------------------
660------500
I am out of my wits trying the best possible way to iterate it. As of now I have managed to filter out the UNIQUE buyers and sellers and items into separate arrays. Any help/tip will be much appreciated.
Thanks ahead

There's most likely a more elegant solution, but anyway
<?php
$dataset = [
[ 'buyer'=>"ACME", 'fees1'=>"100", 'seller'=>"XYZ plc", 'fees2'=>"200", 'item'=>"Bricks" ],
[ 'buyer'=>"ACME", 'fees1'=>"110", 'seller'=>"XYZ plc", 'fees2'=>"220", 'item'=>"Bricks" ],
[ 'buyer'=>"XYZ plc", 'fees1'=>"200", 'seller'=>"ACME", 'fees2'=>"300", 'item'=>"Cement" ],
/* and so on and on */
];
$columns = array_unique(array_column($dataset, 'item'));
//sort($columns);
// create a template with all possible items (as key) and value 0
$template = array_combine(
$columns,
array_pad( array(), count($columns), 0)
);
$result = [];
foreach( $dataset as $row ) {
// if we haven't seen this seller before
if ( !isset($result[ $row['seller'] ]) ) {
// create a template with all possible items but each having 0-value
$result[ $row['seller'] ] = $template;
}
// same for buyer
if ( !isset($result[ $row['buyer'] ]) ) {
$result[ $row['buyer'] ] = $template;
}
// now comes the tricky part
// remember: $result[$row['seller']] === array('Bricks'=>sumFeeBricks, 'Cemtent'=>sumFeeCement)
// i.e. $result[$row['seller']]['Cemtent'] += <something> increases sumFeeCement in the array representing the seller in $result
// $row['item'] tells you which element within $result[$row['seller']] you want to increase
// ==> $result[$row['seller']][$row['item']] += ....
// increase sumFee of the sold item by fee2 for the seller
$result[$row['seller']][ $row['item'] ] += $row['fees2'];
// increase sumFee of the sold item by fee1 for the buyer
$result[$row['buyer']][ $row['item'] ] += $row['fees1'];
}
var_export($result);

Just iterate over the array creating a new multidimensional one. No need to translate the givven array directly to the desired output.

I came with an idea of solving it, if you don't have such a function like array_column (i.e. PHP 5.4.10)
<?php
// we assume, the data is organised in such a way: first buyer/seller/whatever then fees1/fees2/etc, item can be at the end or beginning
$a1 = [
[ 'buyer'=>"ACME", 'fees1'=>"100", 'seller'=>"XYZ plc", 'fees2'=>"200", 'item'=>"Bricks" ],
[ 'buyer'=>"ACME", 'fees1'=>"110", 'seller'=>"XYZ plc", 'fees2'=>"220", 'item'=>"Bricks" ],
[ 'buyer'=>"XYZ Plc", 'fees1'=>"200", 'seller'=>"ACME", 'fees2'=>"300", 'item'=>"Cement" ],
/* and so on and on */
];
function process($obj, $arr){ // we process a single row of $a1
$data = array(); // first we create an indexed array for storing a single key and its value
foreach($obj as $key=>$val){
$key = strtolower($key);
$val = strtolower($val);
$data[] = array($key=>$val);
}
for($i=0;$i<sizeof($data);$i++){ // we iterate over this array
$key = array_pop(array_keys($data[$i])); // we've got current key
$val = $data[$i][$key]; // we've got current value, company
if(preg_match("/buyer|seller/", $key)){ // if it's seller or buyer or whatever we want just edit
$next_key = array_pop(array_keys($data[$i+1])); // we take the next element of $data which is $key=>$value, next key i.e. fees1
$next_val = $data[$i+1][$next_key]; // we take its value e.g. 100
$arr[$val]+=$next_val; // we put the money for company, and adding them up
}
}
return $arr; // the end of processing a single row of $a1
}
$data = array(); // first we create the data split into items buckets
foreach($a1 as $obj){
foreach($obj as $key=>$val){
$key = strtolower($key); // ACME or AcMe, no difference
$val = strtolower($val);
if(preg_match("/item/", $key)){
$data[$val][] = $obj;
}
}
}
print_r($data);
$final = array(); // we store the result for items
foreach($data as $item=>$obj){ // we iterate over items
$arr = array(); // variable for one item, for next we'll start from empty array
foreach($obj as $val){ // we process each row for item
$arr = process($val, $arr);
}
$final[$item] = $arr; // we put processed data to key which is item
}
$total = array(); // we store the total result
foreach($final as $val){
foreach($val as $key=>$prize){
$total[$key]+=$prize; // we add up all money for a single company
}
}
print_r($final);
print_r($total);
?>

Related

Convert a nested Array to Scalar and then reconvert the scalar to nested array

I have an array that looks like this.
$array = [
0 => 'abc',
1 => [
0 => 'def',
1 => 'ghi'
],
'assoc1' => [
'nassoc' => 'jkl',
'nassoc2' => 'mno',
'nassoc3' => '',
'nassoc4' => false
]
];
The $array can have numeric keys or be an assoc array or a mixed one. The level of nesting is not known. Also the values of the array can also be bool or null or an empty string ''
I need to able to convert this into a scalar array with key value pairs. And then later reconvert it back to the exact same array.
So the scalar array could look like
$arrayScalar = [
'0' => 'abc',
'1[0]' => 'def',
'1[1]' => 'ghi',
'assoc1[nassoc]' => 'jkl',
'assoc1[nassoc2]' => 'mno',
'assoc1[nassoc3]' => '',
'assoc1[nassoc4]' => false
];
And then later be able to get back to the initial $array.
I wrote a parser and it does not currently handle bool values correctly.
I have a feeling this is at best a super hacky method to do what I am after. Also I have been able to test it only so much.
function flattenNestedArraysRecursively($nestedArray, $parent = '', &$flattened = [])
{
$keys = array_keys($nestedArray);
if (empty($keys)) {
$flattened[$parent] = 'emptyarray';
} else {
foreach ($keys as $value) {
if (is_array($nestedArray[$value])) {
$reqParent = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$this->flattenNestedArraysRecursively($nestedArray[$value], $reqParent, $flattened);
} else {
$reqKey = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$flattened[$reqKey] = $nestedArray[$value];
}
}
}
return $flattened;
}
function reCreateFlattenedArray($flatArray): array
{
$arr = [];
foreach ($flatArray as $key => $value) {
$keys = explode('|!|', $key);
$arr = $this->reCreateArrayRecursiveWorker($keys, $value, $arr);
}
return $arr;
}
function reCreateArrayRecursiveWorker($keys, $value, $existingArr)
{
//Outside to Inside
$keyCur = array_shift($keys);
//Check if keyCur Exists in the existingArray
if (key_exists($keyCur, $existingArr)) {
// Check if we have reached the deepest level
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// If not then continue to go deeper while appending deeper levels values to current key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, $existingArr[$keyCur]);
return $existingArr;
}
} else {
// If Key does not exists in current Array
// Check deepest
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// Add the key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, []);
return $existingArr;
}
}
}
Is there a better more elegant way of doing this, maybe http_build_query or something else I am not aware of.
Sandbox link -> http://sandbox.onlinephpfunctions.com/code/50b3890e5bdc515bc145eda0a1b34c29eefadcca
Flattening:
Your approach towards recursion is correct. I think we can make it more simpler.
We loop over the array. if the value is an array in itself, we recursively make a call to this new child subarray.
This way, we visit each key and each value. Now, we are only left to manage the keys to assign them when adding to our final resultant array, say $arrayScalar.
For this, we make a new function parameter which takes the parent key into account when assigning. That's it.
Snippet:
$arrayScalar = [];
function flatten($array,&$arrayScalar,$parent_key){
foreach($array as $key => $value){
$curr_key = empty($parent_key) ? $key : $parent_key . '[' . $key . ']';
if(is_array($value)){
flatten($value,$arrayScalar,$curr_key);
}else{
$arrayScalar[$curr_key] = $value;
}
}
}
flatten($array,$arrayScalar,'');
var_export($arrayScalar);
Demo: http://sandbox.onlinephpfunctions.com/code/1e3092e9e163330f43d495cc9d4acb672289a987
Unflattening:
This one is a little tricky.
You might have already noticed that the keys in the flattened array are of the form key1[key2][key3][key4] etc.
So, we collect all these individually in a new array, say $split_key. It might look like this.
array (
'key1',
'key2',
'key3',
'key4',
)
To achieve the above, we do a basic string parsing and added in-between keys to the array whenever we reach the end of the key string or [ or ].
Next, to add them to our final resultant array, we loop over the collected keys and check if they are set in our final array. If not so, set them. We now pass child array reference to our temporary variable $temp. This is to edit the same copy of the array. In the end, we return the result.
Snippet:
<?php
function unflatten($arrayScalar){
$result = [];
foreach($arrayScalar as $key => $value){
if(is_int($key)) $key = strval($key);
$split_key = [];
$key_len = strlen($key);
$curr = '';
// collect them as individual keys
for($i = 0; $i < $key_len; ++$i){
if($key[ $i ] == '[' || $key[ $i ] == ']'){
if(strlen($curr) === 0) continue;
$split_key[] = $curr;
$curr = '';
}else{
$curr .= $key[ $i ];
}
if($i === $key_len - 1 && strlen($curr) > 0){
$split_key[] = $curr;
}
}
// collecting them ends
//add them to our resultant array.
$temp = &$result;
foreach($split_key as $sk){
if(!isset($temp[ $sk ])){
$temp[ $sk ] = [];
}
$temp = &$temp[$sk];
}
$temp = $value;
}
return $result;
}
var_export(unflatten($arrayScalar));
Demo: http://sandbox.onlinephpfunctions.com/code/66136a699c3c5285eed3d3350ed4faa5bbce4b76

Merge multiple object in foreach

I have one or more object in foreach and I want to merge all the objects in one in $refJSON.
$refObj = (object) array();
foreach($items as $item) { //here Im looping Two items
$refObj->refId = $item->getId();
$refObj->refLastName = $item->getLastName();
$refObj->refPhone = $item->getPhone();
$orderObj->refEmail = $item->getEmail();
}
$refJSON = json_encode($orderObj);
var_dump($refJSON);
Output :
//just the last item object
string(92) "{
"refId":"2",
"refLastName":"Joe",
"refPhone":"xxxxxxx",
"refEmail":"example#domaine.com"
}"
The output expected is to merge all the items ids 1 and 2 something like this:
[
{
"refId":"1",
"refLastName":"Steve",
"refPhone":"xxxxxxx",
"refEmail":"foo#domaine.com"
},
{
"refId":"2",
"refLastName":"Joe",
"refPhone":"xxxxxxx",
"refEmail":"example#domaine.com"
}
]
You are just overwriting the same object each time. Build each object and add this to an array (using []) and encode the result...
$refOut = array();
foreach($items as $item) { //here Im looping Two items
$refOut[] = ['refId' => $item->getId(),
'refLastName' => $item->getLastName(),
'refPhone' => $item->getPhone(),
'refEmail' => $item->getEmail()];
}
$refJSON = json_encode($refOut);

push element array laravel

sory help me for add element to array
this code my controller
$datas = PengembalianAset::select('kd_brg', 'nm_brg', 'nm_lgkp_brg', 'keterangan', 'ruang_id', 'no_ikn')
->find($request->id)->toArray();
foreach ($datas as $safety) {
$dataSet[] = [
'new element' => 1,
$safety,
];
}
print_r($dataSet); exit;
array output
and I want to push 1 element to my data
which I expected
but the result is like this
But the result is like this, not what I expected
Try the following :
$datas = PengembalianAset::select('kd_brg', 'nm_brg', 'nm_lgkp_brg', 'keterangan', 'ruang_id', 'no_ikn')->find($request->id)->toArray();
foreach ($datas as $safety) {
$safety['new_element'] = 1;
$dataSet[] = $safety;
}
print_r($dataSet); exit;
or also you can add it to your exist array
$datas = PengembalianAset::select('kd_brg', 'nm_brg', 'nm_lgkp_brg', 'keterangan', 'ruang_id', 'no_ikn')->find($request->id)->toArray();
foreach ($datas as &$safety) { //Passing by Reference
$safety['new element'] = 1
}
print_r($datas); exit;
You can do this also -
$datas = PengembalianAset::select('kd_brg', 'nm_brg', 'nm_lgkp_brg',
'keterangan', 'ruang_id', 'no_ikn', '1 AS `new element`')
->find($request->id)->toArray();
Get 1 as new element from the query only. As it will have the same value. No need for the extra loop.
change your foreach from
foreach ($datas as $safety) {
$dataSet[] = [
'new element' => 1,
$safety,
];
}
to
foreach ($datas as $safety) {
$safety['new element'] = 1;
$dataSet[] = $safety;
}

Using PHP to loop JSON and generate a new format of nested JSON

In PHP, how do I loop through the following JSON Object's date key, if the date value are the same then merge the time:
[
{
date: "27-06-2017",
time: "1430"
},
{
date: "27-06-2017",
time: "1500"
},
{
date: "28-06-2017",
time: "0930"
},
{
date: "28-06-2017",
time: "0915"
}
]
Result should looks like this:
[
{
date: "27-06-2017",
time: [{"1430","1500"}]
}, {
date: "28-06-2017",
time: [{"0930, 0915"}]
}
]
Should I create an empty array, then the looping through the JSON and recreate a new JSON? Is there any better way or any solution to reference?
Thank you!
This solution is a little overhead, but if you are sure that your data is sequential and sorted, you can use array_count_values and array_map:
$count = array_count_values(array_column($array, 'date'));
$times = array_column($array, 'time');
$grouped = array_map(function ($date, $count) use (&$times) {
return [
'date' => $date,
'time' => array_splice($times, 0, $count)
];
}, array_keys($count), $count);
Here is working demo.
Another Idea to do this is
<?php
$string = '[{"date": "27-06-2017","time": "1430"},{"date": "27-06-2017","time": "1500"},{"date": "28-06-2017","time": "0930"},{"date": "28-06-2017","time": "0915"}]';
$arrs = json_decode($string);
$main = array();
$temp = array();
foreach($arrs as $arr){
if(in_array($arr->date,$temp)){
$main[$arr->date]['time'][] = $arr->time;
}else{
$main[$arr->date]['date'] = $arr->date;
$main[$arr->date]['time'][] = $arr->time;
$temp[] = $arr->date;
}
}
echo json_encode($main);
?>
live demo : https://eval.in/787695
Please try this:
$a = [] // Your input array
$op= [];//output array
foreach($a as $key => $val){
$key = $val['date'];
$op[$key][] = $val['time'];
}
$op2 = [];
foreach($op as $key => $val){
$op2[] = ['date' => $key, 'time' => $val];
}
// create the "final" array
$final = [];
// loop the JSON (assigned to $l)
foreach($l as $o) {
// assign $final[{date}] = to be a new object if it doesn't already exist
if(empty($final[$o->date])) {
$final[$o->date] = (object) ['date' => $o->date, 'time' => [$o->time]];
}
// ... otherwise, if it does exist, just append this time to the array
else {
$final[$o->date]->time[] = $o->time;
}
}
// to get you back to a zero-indexed array
$final = array_values($final);
The "final" array is created with date based indexes initially so that you can determine whether they've been set or not to allow you to manipulate the correct "time" arrays.
They're just removed at the end by dropping $final into array_values() to get the zero-indexed array you're after.
json_encode($final) will give you want you want as a JSON:
[{"date":"27-06-2017","time":["1430","1500"]},{"date":"28-06-2017","time":["0930","0915"]}]
Yet another solution :
$d = [];
$dizi = array_map(function ($value) use (&$d) {
if (array_key_exists($value->date, $d)) {
array_push($d[$value->date]['time'], $value->time);
} else {
$d[$value->date] = [
'date' => $value->date,
'time' => [$value->time]
];
}
}, $array);
echo json_encode(array_values($d));

Create multidimensional array from rows of data

I have a database with project entries. Each entry has a project title, datestamp, the user who entered it, and a comment. I am trying to format this data as JSON for reporting and charts.
I want an array for each project name, and inside that array an array for each entry.
I've tried several approaches but I haven't had much luck yet.
if ($result = $mysqli->query("SELECT * FROM project_entries"))
// WHERE WEEK(date) = WEEK(current_date) ORDER BY project_name
{
while ($row = mysqli_fetch_array($result)) {
$entry_array = array();
$row_array['project_name'] = $row['project_name'];
$comment = $row['comment'];
$entry = array (
'comment' => $comment,
);
$row_array['entries'] = $entry;
if ( !in_array($row['project_name'], $projects, false ))
{
array_push($projects, $row_array);
}
}
}
Outputs:
[
{
"project_name": "Logo Design",
"entries": {
"comment": "Worked on a thing"
}
},
{
"project_name": "Logo Design",
"entries": {
"comment": "Created some stuff"
}
},
While I want:
{
"project_name": "Logo Design",
"entries": {
"comment": "Worked on a thing",
"comment": "Created some stuff"
}
}
This should do the trick. You can use the project name as an array key. In order to prevent the string keys from showing up in your output array, you can use array_values to convert them to numeric keys.
$projects = array();
while ($row = mysqli_fetch_array($result)) {
$projects[$row['project_name']]['project_name'] = $row['project_name'];
$projects[$row['project_name']]['entries'][] = array('comment' => $row['comment']);
}
echo json_encode(array_values($projects));
What was going wrong with your previous code:
if ($result = $mysqli->query("SELECT * FROM project_entries")) {
while ($row = mysqli_fetch_array($result)) {
$entry_array = array(); // This does not appear to be used
// With each iteration of the while loop, you create a new array of
// project information (project name and entries array with one comment)
$row_array['project_name'] = $row['project_name'];
$comment = $row['comment'];
$entry = array ('comment' => $comment);
$row_array['entries'] = $entry;
// The $projects array is an array of arrays, but $row['project_name'] is
// a string. Checking if this string is in an array of arrays will always
// be false, so the array_push should always execute.
if (!in_array($row['project_name'], $projects, false )) {
// Adds the new project array to the projects array
array_push($projects, $row_array);
}
// This is not producing what you want because you are adding a new
// array to $row_array each time the loop runs
}
}
Why the code I suggested works:
$projects = array(); // Empty array to hold all the projects
while ($row = mysqli_fetch_array($result)) {
// Using the project name from the database as an array key in the array we are
// constructing keeps the projects unique in that array.
// The first time a new project name occurs, this will create a new sub-array
// within $projects with project_name => the new project name. This value will
// be overwritten on subsequent occurrences of the same project name.
$projects[$row['project_name']]['project_name'] = $row['project_name'];
// For each iteration, this will add a comment to the 'entries' array in the
// project array with the key $row['project_name'].
$projects[$row['project_name']]['entries'][] = array('comment' => $row['comment']);
// For example, with the first iteration of the array we create the following:
//
// $projects['Logo Design'][
// 'project_name' =>'Logo Design',
// 'entries' => [0 => ['comment' => 'Worked on a thing'] ] ]
//
// with the second iteration, the project name is overwritten (with same project name)
// and another comment array is added to the entries array
//
// $projects['Logo Design'][
// 'project_name' =>'Logo Design',
// 'entries' => [0 => ['comment' => 'Worked on a thing'],
// 1 => ['comment' => 'Created some stuff'] ] ]
}
// If you just did echo json_encode($projects), you would not get the format you want,
// because of the string keys. Try it without the array_values() to see what I mean.
echo json_encode(array_values($projects));
Maybe something like that?
Use project id to build target array.
while ($row = mysqli_fetch_array($result) {
if (!isset($projects[$row['id']]))
{
$projects[$row['id']] = [
'project_name' => $row['project_name'],
'entries' => [],
];
}
$projects[$row['id']]['entries'][] = [
'comment' => $row['comment'],
];
}

Categories