Modify key and value inside multidimensional array PHP - php

I'm trying to modify a key and value from a multidimensional array with PHP
[0] => Array (
[price] => 1-0
[shipping] => 0-1
[description] => 0-1
[meta_title] => 0-1
)
[1] => Array (
[price] => 1-0
[shipping] => 0-1
[meta_title] => 0-1
)
Let's say I wanna modify description value and key name in 0, I wanna do with index numbers for some reasons, my code so far and where I'm stucked:
$pageID = 0;
$text_id = 2;
$i=0;
foreach($oJson[$pageID] as $t => $f){
if($i==$text_id){
}
$i++;
}
Desired result:
[0] => Array (
[price] => 1-0
[shipping] => 0-1
[modified_description] => 2-3
[meta_title] => 0-1
)
[1] => Array (
[price] => 1-0
[shipping] => 0-1
[meta_title] => 0-1
)
Thanks a lot for your precious help.

Since you want to keep the associative key order, you can use array_keys, array_values, and array_combine.
$pageID = 0;
$text_id = 2;
$newKeys = array_keys($oJson[$pageID]);
$newValues = array_values($oJson[$pageID]);
$newKeys[$text_id] = 'modified_' . $newKeys[$text_id];
$newValues[$text_id] = '2-3';
$oJson[$pageID] = array_combine($newKeys, $newValues);

Try this:
$oJson = array('0' => Array (
'price' => '1-0',
'shipping' => '0-1',
'description' =>'0-1',
'meta_title' => '0-1',
),
'1' => Array (
'price' => '1-0',
'shipping' => '0-1',
'meta_title' => '0-1',
)
);
$pageID = 0;
$text_id = 2;
foreach($oJson as $key => $subArray)
{
if($key == $pageID)
{
$tempArray = array();
for($i = 0; $i < count($subArray); $i++)
{
if($i == $text_id)
{
$tempArray = array_slice($subArray, 0, $text_id);
$tempArray['modified_description'] = '2-3';
$tempArray = array_merge($tempArray, array_slice($subArray, $text_id + 1));
}
}
if(!empty($tempArray))
$oJson[$key] = $tempArray;
}
}
print_r($oJson);
Working example: CLICK!

Related

php remove empty 'columns' in multidimensional, associative array

Goal: Generate an array that includes only those 'columns' with data, even though a 'header' may exist.
Example Data:
Array (
[HeaderRow] => Array (
[0] => Employee [1] => LaborHours [2] => 0.1 [3] => 0.25 [4] => 0.5 [5] => 0.8
)
[r0] => Array (
[0] => Joe [1] => 5 [2] => [3] => [4] => 50 [5] =>
)
[r1] => Array (
[0] => Fred [1] => 5 [2] => 10 [3] => [4] => [5] =>
)
)
Desired Output:
Array (
[HeaderRow] => Array (
[0] => Employee [1] => LaborHours [2] => 0.1 [4] => 0.5
)
[r0] => Array (
[0] => Joe [1] => 5 [2] => [4] => 50
)
[r1] => Array (
[0] => Fred [1] => 5 [2] => 10 [4] =>
)
)
So, in this very dumbed down example, the HeaderRow will always have data, but if both c0 and c1 are empty (as is the case for [3] and [5]) then I want to remove. I tried iterating through with for loops like I would in other languages, but that apparently doesn't work with associative arrays. I then tried doing a transpose followed by two foreach loops, but that failed me as well. Here's a sample of my for loop attempt:
Attempt with For Loop
for ($j = 0; $j <= count(reset($array))-1; $j++) {
$empty = true;
for ($i = 1; $i <= count($array)-1; $i++) {
if(!empty($array[$i][$j])) {
$empty = false;
break;
}
}
if ($empty === true)
{
for ($i = 0; $i <= count($array); $i++) {
unset($array[$i][$j]);
}
}
}
return $array;
Attempt with transpose:
$array = transpose($array);
foreach ($array as $row)
{
$empty = true;
foreach ($row as $value)
{
if (!empty($value))
{
$empty = false;
}
}
if ($empty) {
unset($array[$row]);
}
}
$array = transpose($array);
return $array;
function transpose($arr) {
$out = array();
foreach ($arr as $key => $subarr) {
foreach ($subarr as $subkey => $subvalue) {
$out[$subkey][$key] = $subvalue;
}
}
return $out;
}
I know the transpose one isn't terribly fleshed out, but I wanted to demonstrate the attempt.
Thanks for any insight.
We can make this more simpler. Just get all column values using array_column.
Use array_filter with a custom callback to remove all empty string values.
If after filtering, size of array is 0, then that key needs to be unset from all
subarrays.
Note: The arrow syntax in the callback is introduced since PHP 7.4.
Snippet:
<?php
$data = array (
'HeaderRow' => Array (
'0' => 'Employee','1' => 'LaborHours', '2' => 0.1, '3' => 0.25, '4' => 0.5, '5' => 0.8
),
'r0' => Array (
'0' => 'Joe', '1' => 5, '2' => '','3' => '', '4' => 50, '5' => ''
),
'r1' => Array (
'0' => 'Fred', '1' => 5,'2' => 10, '3' => '', '4' => '', '5' => ''
)
);
$cleanup_keys = [];
foreach(array_keys($data['HeaderRow']) as $column_key){
$column_values = array_column($data, $column_key);
array_shift($column_values); // removing header row value
$column_values = array_filter($column_values,fn($val) => strlen($val) != 0);
if(count($column_values) == 0) $cleanup_keys[] = $column_key;
}
foreach($data as &$row){
foreach($cleanup_keys as $ck){
unset($row[ $ck ]);
}
}
print_r($data);
It figures, I work on this for a day and have a moment of clarity right after posting. The answer was that I wasn't leveraging the Keys.:
function array_cleanup($array)
{
$array = transpose($array);
foreach ($array as $key => $value)
{
$empty = true;
foreach ($value as $subkey => $subvalue)
{
if ($subkey != "HeaderRow") {
if (!empty($subvalue))
{
$empty = false;
}
}
}
if ($empty) {
unset($array[$key]);
}
}
$array = transpose($array);
return $array;
}

How to merge two arrays diferents on one

How to update an array of objects, adding the quantities if you already have the same ID, or if you have not created a new object.
I tried to explain in the code with the arrays and also with the idea of how I would like the result to be.
old Array
$a1 = [
array(
"id" => 1,
"qty" => 1
),
array(
"id" => 2,
"qty" => 1
)
];
$a2 = [
array(
"id" => 1,
"qty" => 1
)
];
$output = array_merge($a1, $a2);
echo '<pre>';
print_r($output);
echo '</pre>';
Result Error:
Array
(
[0] => Array
(
[id] => 1
[qty] => 1
)
[1] => Array
(
[id] => 2
[qty] => 1
)
[2] => Array
(
[id] => 1
[qty] => 1
)
)
What I need, in addition to if the ID does not contain, add.
Array
(
[0] => Array
(
[id] => 1
[qty] => 2
)
[1] => Array
(
[id] => 2
[qty] => 1
)
)
You can take the first array as base, then search for the key (if existing) where the product matches the id. Then either add the quantity and recalculate the price or you just add the reformatted element (id to product conversion).
$result = $a;
foreach($b as $element) {
$matchingProductIndex = array_search($element['id'], array_column($a, 'product'));
if ($matchingProductIndex !== false) {
$pricePerUnit = $result[$matchingProductIndex]['price'] / $result[$matchingProductIndex]['qty'];
$result[$matchingProductIndex]['qty'] += $element['qty'];
$result[$matchingProductIndex]['price'] = $result[$matchingProductIndex]['qty'] * $pricePerUnit;
} else {
$result[] = [
'qty' => $element['qty'],
'product' => $element['id'],
'price' => $element['price'],
];
}
}
print_r($result);
Working example.
Loop through both arrays with foreach and check the ids against each other.
https://paiza.io/projects/lnnl5HeJSFIOz_6KD6HRIw
<?php
$arr1 = [['qty' => 4, 'id' => 4],['qty' => 1,'id' => 30]];
$arr2 = [['id' => 30, 'qty' => 19],['id' => 31, 'qty' => 2]];
$arr3 = [];
foreach($arr1 as $iArr1){
$match = false;
foreach($arr2 as $iArr2){
if($iArr1['id'] === $iArr2['id']){
$arr3[] = ['id' => $iArr1['id'], 'qty' => $iArr1['qty'] + $iArr2['qty']];
$match = true;
}
}
if(!$match){
$arr3[] = $iArr1;
$arr3[] = $iArr2;
}
}
print_r($arr3);
?>
One approach could be one I more often suggested.
First lets merge $a2 with one to simplify looping over one larger collection.
If we then create a small mapping from id to its index in the result array we can update the running total of qty.
$map = [];
$result = [];
// Merge the two and do as per usual, create a mapping
// from id to index and update the qty at the corresponding index.
foreach (array_merge($a1, $a2) as $subarr) {
$id = $subarr['id'];
if (!key_exists($id, $map)) {
$index = array_push($result, $subarr) - 1;
$map[$id] = $index;
continue;
}
$result[$map[$id]]['qty'] += $subarr['qty'];
}
echo '<pre>', print_r($result, true), '</pre>';
Output:
Array
(
[0] => Array
(
[id] => 1
[qty] => 2
)
[1] => Array
(
[id] => 2
[qty] => 1
)
)

How to group keys and values of an (sub)array and sum its values using PHP? [duplicate]

This question already has answers here:
Group array data on one column and sum data from another column
(5 answers)
Closed 9 months ago.
I have the following array
Array (
[0] => Array
(
[0] => ALFA
[1] => 213
)
[1] => Array
(
[0] => ALFA
[1] => 151
)
[2] => Array
(
[0] => ALFA
[1] => 197
)
[3] => Array
(
[0] => BETA
[1] => 167
)
[4] => Array
(
[0] => ZETA
[1] => 254
)
[5] => Array
(
[0] => GAMA
[1] => 138
)
[6] => Array
(
[0] => GAMA
[1] => 213
)
)
And I would like to group the key[0] of the subarray so I can see how many equal keys it has.
Something like that:
ALFA => 3
BETA => 1
EPSI => 1
GAMA => 2
I tried with array_count_values, but without success.
foreach ($array as $value) {
echo '<pre>';
print_r(array_count_values($value));
echo '</pre>';
}
With that we have following result:
Array
(
[ALFA] => 1
[213] => 1
)
Array
(
[ALFA] => 1
[151] => 1
)
...
Array
(
[GAMA] => 1
[213] => 1
)
And after that I would like to sum the values of each group as well.
ALFA => 213 + 151 + 197
BETA => 167
ZETA => 254
GAMA => 138 + 213
I think that when we solve the first part of the problem, the second would follow easier with quite the same method.
The final purpose is to divide the sum of values by the number of occurrences of each key group, so we can have an average of the values just like that:
ALFA => (213+151+197) / 3 = 187
BETA => 167
ZETA => 254
GAMA => (138+213) / 2 = 175,5
This is not the main problem, but as I said, I'm stuck with the beginning of the solution and would appreciate any help.
I'm surprised at all the long and complicated answers. However, the initial foreach to model your data to something manageable is needed. After that you just need to do a really simple array_walk.
<?php
$result = array();
foreach ($array as $el) {
if (!array_key_exists($el[0], $result)) {
$result[$el[0]] = array();
}
$result[$el[0]][] = $el[1];
}
array_walk($result, create_function('&$v,$k', '$v = array_sum($v) / count($v);'));
?>
Result:
Array
(
[ALFA] => 187
[BETA] => 167
[ZETA] => 254
[GAMA] => 175.5
)
Solution for you is here:
Code:
$input = [
['alfa', 123],
['alfa', 223],
['alfa', 122],
['alfa', 554],
['alfa', 34],
['dalfa', 123],
['halfa', 223],
['dalfa', 122],
['halfa', 554],
['ralfa', 34]
];
$result = [];
foreach ($input as $node) {
if (isset($result[$node[0]])) {
$result[$node[0]] = ['sum' => $result[$node[0]]['sum'] + $node[1], 'count' => $result[$node[0]]['count'] + 1];
} else {
$result[$node[0]] = ['sum' => $node[1], 'count' => 1];
}
}
print_r($result);
foreach ($result as $key => &$data) {
$data = $data['sum'] / $data['count'];
}
print_r($result);
Output:
Array
(
[alfa] => Array
(
[sum] => 1056
[count] => 5
)
[dalfa] => Array
(
[sum] => 245
[count] => 2
)
[halfa] => Array
(
[sum] => 777
[count] => 2
)
[ralfa] => Array
(
[sum] => 34
[count] => 1
)
)
Array
(
[alfa] => 211.2
[dalfa] => 122.5
[halfa] => 388.5
[ralfa] => 34
)
$sort = array();
foreach ($array as $value) {
$sort[$value[0]][] = $value[1];
}
then you count how many keys each has
$keys = array();
foreach($sort as $k => $v) {
$keys[$k] = count($v);
}
then for calculating the amount
$sum = array();
$average = array();
foreach($sort as $k => $v) {
$amount = 0;
foreach($v as $val) {
$amount += $val;
}
$sum[$k] = $amount;
$average[$k] = $amount / $keys[$k];
}
HOWEVER, If you want all the details in one array:
$final = array();
foreach ($array as $value) {
$final[$value[0]]["values"][] = $value[1];
}
foreach($final as $k => $v) {
$final[$k]["amount"] = count($v['values']);
$amount = 0;
foreach($v['values'] as $val) {
$amount += $val;
}
$final[$k]["sum"] = $amount;
$final[$k]["average"] = $amount / $final[$k]["amount"];
}
example: http://jdl-enterprises.co.uk/sof/25789697.php
Includes Output
Just copy the codes to your favorite text editor, sure it works perfectly.
$items = [
['ALFA',213],
['ALFA',151],
['ALFA',197],
['BETA',167],
['ZETA',254],
['GAMA',138],
['GAMA',213]
];
echo '<pre>' . print_r($items,true) . '</pre>';
$result;
foreach ($items as $value) {
# code...
if (isset($result[$value[0]])) {
$sum = $result[$value[0]]['sum'] + $value[1];
$count = $result[$value[0]]['count'] + 1;
$result[$value[0]] = ['sum' => $sum , 'count' => $count, 'divided' => ($sum / $count)];
} else {
$result[$value[0]] = ['sum' => $value[1] , 'count' => 1 , 'divided' => ($value[1] / 1) ];
}
}
echo '<pre>' . print_r($result,true) . '</pre>';
$myArray = [
["ALFA",213],
["ALFA",151],
["ALFA",197],
["BETA",167],
["ZETA",254],
["GAMA",138],
["GAMA",213]
];
$a1 = array(); //TEMPORARY ARRAY FOR KEEPING COUNT & TOTAL VALUES
$res = array(); //ARRAY USED TO KEEP RESULT
foreach($myArray as $val)
{
//AVOID PESKY NOTICES FOR UNDEFINED INDEXES
if ( !array_key_exists($val[0],$a1) ) {
$a1[$val[0]] = array("count" => 0,"total" => 0);
$res[$val[0]] = 0;
}
//INCREMENT THE COUNT OF INSTANCES OF THIS KEY
$a1[$val[0]]["count"]++;
//INCREMENT THE TOTAL VALUE OF INSTANCES OF THIS KEY
$a1[$val[0]]["total"]+=$val[1];
// UPDATE RESULT ARRAY
$res[$val[0]] = $a1[$val[0]]["total"] / $a1[$val[0]]["count"];
}
print_r($res);
Should result in:
Array
(
[ALFA] => 187
[BETA] => 167
[ZETA] => 254
[GAMA] => 175.5
)
Sample: http://phpfiddle.org/lite/code/a7nt-5svf

PHP Counting inside an Array

I want to create a list where if its already in the array to add to the value +1.
Current Output
[1] => Array
(
[source] => 397
[value] => 1
)
[2] => Array
(
[source] => 397
[value] => 1
)
[3] => Array
(
[source] => 1314
[value] => 1
)
What I want to Achieve
[1] => Array
(
[source] => 397
[value] => 2
)
[2] => Array
(
[source] => 1314
[value] => 1
)
My current dulled down PHP
foreach ($submissions as $timefix) {
//Start countng
$data = array(
'source' => $timefix['parent']['id'],
'value' => '1'
);
$dataJson[] = $data;
}
print_r($dataJson);
Simply use an associated array:
$dataJson = array();
foreach ($submissions as $timefix) {
$id = $timefix['parent']['id'];
if (!isset($dataJson[$id])) {
$dataJson[$id] = array('source' => $id, 'value' => 1);
} else {
$dataJson[$id]['value']++;
}
}
$dataJson = array_values($dataJson); // reset the keys - you don't nessesarily need this
This is not exactly your desired output, as the array keys are not preserved, but if it suits you, you could use the item ID as the array key. This would simplify your code to the point of not needing to loop through the already available results:
foreach ($submissions as $timefix) {
$id = $timefix['parent']['id'];
if (array_key_exists($id, $dataJson)) {
$dataJson[$id]["value"]++;
} else {
$dataJson[$id] = [
"source" => $id,
"value" => 1
];
}
}
print_r($dataJson);
You should simplify this for yourself. Something like:
<?
$res = Array();
foreach ($original as $item) {
if (!isset($res[$item['source']])) $res[$item['source']] = $item['value'];
else $res[$item['source']] += $item['value'];
}
?>
After this, you will have array $res which will be something like:
Array(
[397] => 2,
[1314] => 1
)
Then, if you really need the format specified, you can use something like:
<?
$final = Array();
foreach ($res as $source=>$value) $final[] = Array(
'source' => $source,
'value' => $value
);
?>
This code will do the counting and produce a $new array as described in your example.
$data = array(
array('source' => 397, 'value' => 1),
array('source' => 397, 'value' => 1),
array('source' => 1314, 'value' => 1),
);
$new = array();
foreach ($data as $item)
{
$source = $item['source'];
if (isset($new[$source]))
$new[$source]['value'] += $item['value'];
else
$new[$source] = $item;
}
$new = array_values($new);
PHP has a function called array_count_values for that. May be you can use it
Example:
<?php
$array = array(1, "hello", 1, "world", "hello");
print_r(array_count_values($array));
?>
Output:
Array
(
[1] => 2
[hello] => 2
[world] => 1
)

array grouping which contains same fields

I have an array which contains following values.
array(
'dates' => array(
(int) 0 => '2013-04-22',
(int) 1 => '2013-04-23',
),
'publisherName' => array(
(int) 0 => 'Comp1',
(int) 1 => 'Comp2',
),
'loaded' => array(
(int) 0 => (int) 2189,
(int) 1 => (int) 37,
),
'clicks' => array(
(int) 0 => (int) 0,
(int) 1 => (int) 0,
),
'ctr' => array(
(int) 0 => (int) 0,
(int) 1 => (int) 0,
)
)
What I want to produce is getting company based data on different dates like the array below.
How am I able to create an array which is like;
array (
'2013-04-22'=>array(
'publisherName'=>'Comp1',
'loaded'=>2189,
'clicks'=>0,
'ctr'=>0),
'2013-04-23'=>array(
'publisherName'=>'Comp2',
'loaded'=>37,
'clicks'=>0,
'ctr'=>0)
...
)
Which contains daily stats but which comes from publishername field.
Any ideas?
Here's an example that doesn't rely on any keys, the only requirement is that date is the first array in your original array:
// $array is your original array
$dates = array_shift($array);
$output = array();
foreach ($array as $k => $a) {
foreach ($a as $i => $v) {
$output[$i][$k] = $v;
}
}
$output = array_combine($dates, $output);
Let the initial array be $a and the desired array $b;
Code:
$b = array();
$count = 0;
foreach($a['dates'] as $date) {
$b[$date] = array(
'name' => $a['publisherName'][$count],
'loaded'=> $a['loaded'][$count],
'clicks'=> $a['clicks'][$count],
'ctr'=> $a['ctr'][$count]
);
$count++;
}
Result:
Array
(
[2013-04-22] => Array
(
[name] => Comp1
[loaded] => 2189
[clicks] => 0
[ctr] => 0
)
[2013-04-23] => Array
(
[name] => Comp2
[loaded] => 37
[clicks] => 0
[ctr] => 0
)
)
<?php
$data = $yourarray;
$new = array();
foreach($data['dates'] as $key=>$value) {
$new[$value] = array('name'=>$data['publisherName'][$key],'loaded'=>$data['loaded'][$key],'clicks'=>$data['clicks'][$key],'ctr'=>$data['ctr'][$key]);
}
echo '<pre>';
print_r($new);
?>
$newArr = array();
foreach($data['dates'] as $key=>$value) {
$new[$value] = array('name'=>$data['publisherName'][$key],'loaded'=>$data['loaded'][$key],'clicks'=>$data['clicks'][$key],'ctr'=>$data['ctr'][$key]);
}
echo '<pre>';
print_r($newArr);
$new_arr = your array;
$finalArray = array();
foreach($new_arr['dates'] as $key => $value){
$finalArray[$value] = array(
'publisherName'=>$new_arr['publisherName'][$key],
'loaded'=>$new_arr['loaded'][$key],
'clicks'=>$new_arr['clicks'][$key],
'ctr'=>$new_arr['ctr'][$key]
);
}
Output :
Array
(
[2013-04-22] => Array
(
[publisherName] => Comp1
[loaded] => 2189
[clicks] => 0
[ctr] => 0
)
[2013-04-23] => Array
(
[publisherName] => Comp2
[loaded] => 37
[clicks] => 0
[ctr] => 0
)
)

Categories