Basic array build - php

Guess this is a basic question.
How can I make an array similar to this, using a foreach loop?
[
[
'ProductGuid' => '27760c24',
'BaseAmountValue' => 240,
'Quantity' => 1,
'Discount' => 0,
'AccountNumber' => 1000,
'Unit' => 'parts',
],
[
'ProductGuid' => '27760c24',
'BaseAmountValue' => 250,
'Quantity' => 1,
'Discount' => 0,
'AccountNumber' => 1000,
'Unit' => 'parts',
]
],
The following is rejected by the API, i'm trying to connect to:
$arr = array();
foreach($items as $item) {
$arr[]['ProductGuid'] = $item->guid;
$arr[]['BaseAmountValue'] = $item->price;
$arr[]['Quantity'] = $item->qty;
$arr[]['Discount'] = $item->discount;
$arr[]['AccountNumber'] = 1000;
$arr[]['Unit'] = 'parts';
}
Hope one of you will be able to help me :)

An alternative to the other two correct answers but without manually setting the array index or use any temporary variables:
$arr = [];
foreach($items as $item) {
$arr[] = [
'ProductGuid' => $item->guid,
'BaseAmountValue' => $item->price,
'Quantity' => $item->qty,
'Discount' => $item->discount,
'AccountNumber' => 1000,
'Unit' => 'parts',
];
}
Martin explained the actual issue so well so no need to go through it again.

Using the given code, you create new inner rows in your array in each line of that loop. The following code will solve that:
$arr = array();
foreach($items as $item) {
$mappedItem = [];
$mappedItem['ProductGuid'] = $item->guid;
$mappedItem['BaseAmountValue'] = $item->price;
$mappedItem['Quantity'] = $item->qty;
$mappedItem['Discount'] = $item->discount;
$mappedItem['AccountNumber'] = 1000;
$mappedItem['Unit'] = 'parts';
$arr[] = $mappedItem;
}

You're fairly close to one way of doing this...
Explanation:
$arr[]['ProductGuid'] = $item->guid;
^^
\= Next numeric array key.
What this is doing is setting the productGuid key on the next numeric outer array, so in effect what you're actually setting is:
$arr[0]['ProductGuid'] = $item->guid;
$arr[1]['BaseAmountValue'] = $item->price;
$arr[2]['Quantity'] = $item->qty;
$arr[3]['Discount'] = $item->discount;
$arr[4]['AccountNumber'] = 1000;
$arr[5]['Unit'] = 'parts';
Which is clearly not what you want.
One Solution:
Therefore you will have to set the array key value on each iteration of the foreach loop.
One way of doing this is manually setting an iterator integer key value:
$arr = [];
$x = 0;
foreach($items as $item) {
$arr[$x]['ProductGuid'] = $item->guid;
$arr[$x]['BaseAmountValue'] = $item->price;
$arr[$x]['Quantity'] = $item->qty;
$arr[$x]['Discount'] = $item->discount;
$arr[$x]['AccountNumber'] = 1000;
$arr[$x]['Unit'] = 'parts';
$x++; // +1 to value of $x
}
Edit:
Nico's way of doing this is a bit neater and a bit smarter.

Related

Convert array variables to associative array [duplicate]

This question already has answers here:
for vs foreach vs while which is faster for iterating through arrays in php
(6 answers)
Closed 3 years ago.
In PHP, what is quickest way to turn the following array variables:
$id = [11,12,13];
$code = ['1234','5678','9012'];
$qty = [3,4,5];
$amount = [12.34,23.45,34.56];
Into an array of associative arrays, like the following:
[
['id'=>11,'code'=>'1234','qty'=>3,'amount'=>12.34],
['id'=>12,'code'=>'5678','qty'=>4,'amount'=>23.45],
['id'=>13,'code'=>'9012','qty'=>5,'amount'=>34.56],
]
Currently, I'm doing the following to convert the data.
$max = count($id);
$data = [];
for ($i=0; $i<$max; $i++) {
$data[] = [
'id' => $id[$i],
'code' => $code[$i],
'qty' => $qty[$i],
'amount' => $amount[$i]
];
}
My application does this a lot, and looking if there are ways to decrease processing time.
Currently using PHP version 5.6
foreach is typically the fastest method of the "general" approaches used to accomplish your desired end-results. This is due to the count() call prior to issuing for() accompanied with an incremental variable to determine the size and placement of the array to iterate over.
Benchmarks: https://3v4l.org/ejIl5
Benchmark 1-5000 https://3v4l.org/IOlAm
$data = [];
foreach($id as $i => $v) {
$data[] = [
'id' => $v,
'code' => $code[$i],
'qty' => $qty[$i],
'amount' => $amount[$i]
];
}
//Execution time: ~0.00000200 seconds
$max = count($id);
$data = [];
for ($i=0; $i<$max; $i++) {
$data[] = [
'id' => $id[$i],
'code' => $code[$i],
'qty' => $qty[$i],
'amount' => $amount[$i]
];
}
//Execution time ~0.00000600 seconds
array_map was the slowest
$data = array_map(function($a, $b, $c, $d) {
return [
'id' => $a,
'code' => $b,
'qty' => $c,
'amount' => $d
];
}, $id, $code, $qty, $amount);
//Execution time: ~0.00001000 seconds
The benchmark used executes a dry-run for each of the approaches to
reduce OP code optimization issues that would typically be implemented
in a production environment.
As an added bonus from the "general" approaches, I also ran a benchmark of an optimized version of the double-ended iteration approach (for ($i=0; $i<ceil($max/2); $i++)). https://3v4l.org/KHUul and 1-5000 https://3v4l.org/Mg95n which had wildly different values with the smaller array sizes, ranging from 0.00030208 seconds to 0.00000095 seconds, but on average was slower than the general for() loop.
As with any benchmarks, the results may vary for your particular environment, settings and are only meant to serve as a generalization of what could be. Please be sure to benchmark your preferred methods in your specific environment to determine which is best.
you can use foreach as well. I am not sure it will more efficient way but it can help you.
$id = [11,12,13];
$code = ['1234','5678','9012'];
$qty = [3,4,5];
$amount = [12.34,23.45,34.56];
foreach ($id as $key=>$val)
{
$array[$key]["id"]= $val;
$array[$key]["code"]= $code[$key];
$array[$key]["qty"]= $qty[$key];
$array[$key]["amount"]= $amount[$key];
}
My below code will optimize the loop by reducing the loop execution to half and will gives your expected result.
$id = [11,12,13,56,34,23,34];
$code = ['1234','5678','9012','4343','4543','4642','534'];
$qty = [3,4,5,6,7,8,3];
$amount = [12.34,23.45,34.56,66.34,75.32,54.3,23.2];
$max = count($id);
$loopRun = 0;
$data = [];
$halfCount = ceil($max/2);
for ($i=0; $i < $halfCount; $i++) {
$loopRun++;
$data[$i] = [
'id' => $id[$i],
'code' => $code[$i],
'qty' => $qty[$i],
'amount' => $amount[$i]
];
$data[$max-($i+1)] = [
'id' => $id[$max-($i+1)],
'code' => $code[$max-($i+1)],
'qty' => $qty[$max-($i+1)],
'amount' => $amount[$max-($i+1)]
];
}
echo "Loop Run Count : ".$loopRun."<br>";
ksort($data);
Demo Link

Push second array inside first array

I have two array containing some value.
$type = array("first", "second", "third");
$date = array(
0 => "2019-04-30",
1 => "2019-05-01",
2 => "2019-05-02",
3 => "2019-05-03"
);
I need output something like this:
[
type :first,
date: [
"2019-04-30": 1.2,
.....
]
]
But for some reason I am not getting in that format.
This is the code I have tried.
$newArr = array();
foreach($type as $tt) {
$newArr[]['type'] = $tt;
$newDate = array();
foreach ($date as $d) {
$newDate[$d] = 1.2;
}
$newArr[]['date'] = $newDate;
}
Can anybody show what I did mistake.
Thank You.
It just comes down to building the array and then adding it in the right order, this builds all of the data and adds it in one go at the end of the loop...
$newArr = array();
foreach($type as $tt) {
$newDate = array();
foreach ($date as $d) {
$newDate[$d] = 1.2;
}
$newArr[] = [ 'type' => $tt, 'date' => $newDate];
}
You could shorten it to this, but it doesn't really make much difference...
foreach($type as $tt) {
$newArr[] = [ 'type' => $tt, 'date' => array_fill_keys($date, 1.2)];
}
Lets make it more simple
$newArr = array();
$newdates = array();
foreach($dates as $date){
$newdates[$date] = 1.2;
}
foreach($type as $tt) {
$newArry[] = array("type"=>$tt,"date"=>$newdates);
}
You can use array_map and array_fill_keys for the desired result
$type = ["first", "second", "third"];
$date = [
0 => "2019-04-30",
1 => "2019-05-01",
2 => "2019-05-02",
3 => "2019-05-03"
];
$newArr = [];
array_map(function($t, $d) use ($date, &$newArr){
$newArr[] = [
'type' => $t,
'date' => array_fill_keys($date, 1.2)
];
}, $type, $date);

Joining rows from two 2d arrays where a common column value is found

I have two arrays that I would like to join into one. Both arrays have a common key=>value and I would like to insert the values of one array to the other so that I to create one array.
$array1 = [
['ID' => 123456, 'Key' => 1000, 'value' => 123.45],
['ID' => 789012, 'Key' => 1001, 'value' => 56748.17],
];
$array2 = [
['Key' => 1000, 'description' => 'desc1'],
['Key' => 1001, 'description' => 'desc2'],
];
I would like to join Array2 with Array1 so that the resulting Array is as follows:
array (
0 =>
array (
'ID' => 123456,
'Key' => 1000,
'value' => 123.45,
'description' => 'desc1',
),
1 =>
array (
'ID' => 789012,
'Key' => 1001,
'value' => 56748.17,
'description' => 'desc2',
),
)
So the arrays have been joined using the [Key] value as the, well, key. I've looked at array_merge and other function but I can't seem to get these two arrays to "merge" properly.
try this, its linear
$keyval = array();
foreach($array1 as $item)$keyval[$item['Key']] = $item['value'];
foreach($array2 as $key=>$item)$array2[$key]['description'] = isset($keyval[$item['Key']]) ? $keyval[$item['Key']] : '';
You would have to do something like
$result = array();
foreach ($a1 as $v1)
{
foreach ($a2 as $k2 => $v2)
{
if ($v1['Key'] === $v2['Key'])
{
$result[] = array_merge($v1, $v2);
unset($a2[$k2]);
break;
}
}
}
Version with for loops
$result = array();
$c_a1 = count($a1);
$c_a2 = count($a2);
for ($i = 0; $i < $c_a1; $i++)
{
for ($j = 0; $j < $c_a2; $j++)
{
if ($a1[$i]['Key'] === $a2[$j]['Key'])
{
$result[] = array_merge($a1[$i], $a2[$j]);
unset($a2[$j]);
$c_a2--;
break;
}
}
}
This is my approach:
$temp_ array = array_fill_keys (array_map(create_function('$a', 'return $a["Key"];'), $array_1) , $array_1);
$result = array();
foreach ($array_2 as $item) {
if (isset($temp_array[$item['Key']])) {
$result[] = array_merge($item, $temp_array[$item['Key']]);
}
}
I have elaborated more in the code above, and reached this improved version:
function array_merge_items_by_common_key_value($key, $array_1, $array_2)
{
$result = array();
$temp_ array = array_fill_keys(array_map(create_function('$a', 'return $a["' . $key . '"];'), $array_1) , $array_1);
foreach ($array_2 as $item)
{
$result[$item[$key]] = isset($temp_array[$item[$key]]) ? array_merge($item, $temp_array[$item[$key]]) : $item;
}
return array_values(array_merge($result, array_diff_key($array_1, $result)));
}
$merged_arrays = array_merge_items_by_common_key_value('Key', $temp_array, $array_2);
First, a temporary array is created: it is equal to $array_1, but its keys are the values to be matched.
Then, $array_2 is looped. When a match is found, the merge is done. If there is no match, then the $array_2 value is maintained, untouched.
Finally, those values in the $array_1 which were not matched, are also appended to the resulting array.
So, no item of both $array_1 or $array_2 is lost, while the matched items are merged.
#radashk's solution will work if you can always guarantee that $array1[$i] corresponds to $array2[$i]. From my reading of the question, that's not guaranteed, but instead you want to make sure that $array1[$i]['Key'] == $array2[$j]['Key'], and combine elements where those Keys match.
There may be a more elegant solution, but I would do it like this:
// builds up new $tmpArray, using the Key as the index
$tmpArray = array();
foreach($array1 as $innerArray1){
$tmpArray[$innerArray1['Key']] = $innerArray1;
}
//Merges the values from $array2 into $tmpArray
foreach($array2 as $innerArray2) {
if (isset($tmpArray[$innerArray2['Key']])) {
$tmpArray[$innerArray2['Key']] = array_merge($tmpArray[$innerArray2['Key']], $innerArray2);
}else{
$tmpArray[$innerArray2['Key']] = $innerArray2;
}
}
Use temporary first level keys to swiftly identify matching Key values between the two arrays. When an array2 row qualifies for merger with the first, use the union-assignment operator (+=). Call array_value() after looping if you don't want to preserve the temporary keys.
Code: (Demo)
$result = array_column($array1, null, 'Key');
foreach ($array2 as $row) {
if (isset($result[$row['Key']])) {
$result[$row['Key']] += $row;
}
}
var_export(array_values($result));

JSON - using PHP's push_array

can someone please explain to me why the first one is working and the second one not? The result is in the second example simply "1".
1.
$c = 0;
$list = array();
foreach ($places as $place) {
$arr = array();
$arr[0] = get_object_vars($place);
$list[$c] = $arr;
$c++;
}
echo json_encode(array("status" => "true", "list" => $list));
2.
$list = array();
foreach ($places as $place) {
array_push($list, get_object_vars($place));
}
echo json_encode(array("status" => "true", "list" => $list));
Sample data for both code samples:
$places = array();
$place = new StdClass;
$place->name = 'first';
$place->location = array('x' => 0.0, 'y' => 0.0);
$places[] = $place;
$place = new StdClass;
$place->name = 'Greenwich Observatory';
$place->location = array('x' => 51.4778, 'y' => 0.0017);
$place->elevation = '65.79m';
$places[] = $place;
In the first case you are adding a key value pair to the array, in the second case just the value. I believe just adding the value SHOULD in fact work, but maybe
foreach ($places as $place) {
array_push($list, array( 0 => get_object_vars($place) );
}
will work better?

Convert multidimensional array to nested set array

im having a little problem i need some help with.
Im trying to convert a multidimensional array into a flatten array with nested set values right and left like so:
$array = {
'id' => 1
'name' => 'john'
'childs' => array(
array(
'id' => 1
'name' => 'jane'
)
)
}
to
$array = {
array(
'id' => 1,
'name' => 'john'
'left' => '1'
'right' => '4'
),
array(
'id' => 1,
'name' => 'jane'
'left' => '2'
'right' => '3'
)
}
Any help is appreciated!
I asked a very similar question and got a result, so thought I'd send it on for you. I realise this is quite an old topic, but still worth getting an answer. I've included my data, but would be easily adapted for yours.
$JSON = '[{"id":1,"children":[{"id":2,"children":[{"id":3},{"id":4}]},{"id":5}]}]';
$cleanJSON = json_decode($JSON,true);
$a_newTree = array();
function recurseTree($structure,$previousLeft)
{
global $a_newTree; // Get global Variable to store results in.
$indexed = array(); // Bucket of results.
$indexed['id'] = $structure['id']; // Set ID
$indexed['left'] = $previousLeft + 1; // Set Left
$lastRight = $indexed['left'];
$i_count = 0;
if ($structure['children'])
{
foreach ($structure['children'] as $a_child)
{
$lastRight = recurseTree($structure['children'][$i_count],$lastRight);
$i_count++;
}
}
$indexed['right'] = $lastRight + 1; // Set Right
array_push($a_newTree,$indexed); // Push onto stack
return $indexed['right'];
}
recurseTree($cleanJSON[0],0);
print_r($a_newTree);
function restructRecursive($array, $left = 1) {
if (isset($array['childs'])) {
$result = array();
foreach ($array['childs'] as $child) {
$result = array_merge($result, restructRecursive($child, $left+1));
}
unset($array['childs']);
}
$array['left'] = $left;
return array_merge(array($array), $result);
}
$newStruct = restructRecursive($oldStruct);
For anyone coming here and looking for a solution, loneTraceur's solution works fine. However, I needed one in OOP, so here is my version of it.
<?php
class NestedSet
{
protected $tree = [];
public function deconstruct($tree, $left = 0)
{
$this->flattenTree($tree, $left);
return $this->tree;
}
protected function flattenTree($tree, $left)
{
$indexed = [];
$indexed['id'] = $tree['id'];
$indexed['_lft'] = $left + 1;
$right = $indexed['_lft'];
if (isset($tree['children']) && count($tree['children'])) {
foreach ($tree['children'] as $child) {
$right = $this->flattenTree($child, $right);
}
}
$indexed['_rgt'] = $right + 1;
$this->tree[] = $indexed;
return $indexed['_rgt'];
}
}
You would run it like this:
$NestedSet = new NestedSet;
$flat = $NestedSet->deconstruct($tree):
This code is based on the other answer.

Categories