Sum of array values based on similar values from another array - php

This might be a little confusing, but I am going to explain it as best as I can. Please bear with me.
I have the following arrays:
Array
(
[question1] => 69
[question2] => 36
[question3] => 57
[question4] => 69
[question5] => 58
[question6] => 40
[question7] => 58
)
Array
(
[question1] => 8
[question2] => 6
[question3] => 5
[question4] => 6
[question5] => 7
[question6] => 8
[question7] => 5
)
As you can see the two arrays have identical keys, but different values for each key.
I need to find the keys in the second array that have the same values, so [question1] and [question6] both have a value of 8. And then in the first array I need to add together the values of [question1] and [question6] because they have a like value in the second array. I need to add the first array values together based on matching values in the second array (if that makes any sense)
Ideally, the output would be another array that would look something like this:
Array
(
[5] => 115
[8] => 109
[6] => 105
[7] => 58
)
Where the value of the second array becomes the key and the sum of the added values from the first array is the value.
Now I won't be picky here, so if we can't get it into that exact format then that is okay. I just need to be able to add together the values in the first array based on the similar values in the second array.
I hope this makes sense. If it doesn't please comment and I will do my best to explain further.

The simplest solution is to iterate over the second array. Lookup the key into the first array and if it exists then add the corresponding value from the first array into the result array, indexed by the value from the second array.
Something like this:
$array1 = array(
'question1' => 69,
'question2' => 36,
'question3' => 57,
'question4' => 69,
'question5' => 58,
'question6' => 40,
'question7' => 58,
);
$array2 = array(
'question1' => 8,
'question2' => 6,
'question3' => 5,
'question4' => 6,
'question5' => 7,
'question6' => 8,
'question7' => 5,
);
// Compose the desired result here
$result = array();
// Iterate over the second array; its values become keys in the result array
foreach ($array2 as $key => $val) {
// If this is the first time when this value is reached then a corresponding
// value does not yet exists in the result array; add it
if (! isset($result[$val])) {
$result[$val] = 0;
}
// Lookup the key into the first array
if (isset($array1[$key])) {
// If it exists then add its value to the results
$result[$val] += $array1[$key];
}
}
// That's all
print_r($result);

Related

Get values of array using as key values of another array

I have an array with some values (numeric values):
$arr1 = [1, 3, 8, 12, 23]
and I have another associative array that a key (which matches to a value of $arr1) correspond to a value. This array may contain also keys that don't match with $arr1.
$arr2 = [1 => "foo", 2 => "foo98", 3 => "foo20", 8 => "foo02", 12 => "foo39", 15 => "foo44", 23 => "foo91", 34 => "foo77"]
I want as return the values of $arr2 specifying as key the values of $arr1:
["foo", "foo20", "foo02", "foo39", "foo91"]
If possible, all this, without loops, using just PHP array native functions (so in an elegant way), or at least with the minimum number of loops possible.
Minimal loop is simple - 1. as:
foreach($arr1 as $k) {
$res[] = $arr2[$k];
}
You can do that with array_walk but I think this simple way is more readable.
If you insist you can do with array_filter + array_values + in_array as:
$res = array_values(array_filter($arr2,
function ($key) use ($arr1) { return in_array($key, $arr1);},
ARRAY_FILTER_USE_KEY
));
You can see this for more about filtering keys
To do it purely with array functions, you could do it as...
print_r(array_intersect_key($arr2, array_flip($arr1) ));
So array_flip() turns the items you want form the array into the keys for $arr1 and then uses array_intersect_key() to match the keys with the main array and this newly created array.
Gives...
Array
(
[1] => foo
[3] => foo20
[8] => foo02
[12] => foo39
[23] => foo91
)
If you don't want the keys - add array_values() around the rest of the calls...
print_r(array_values(array_intersect_key($arr2, array_flip($arr1) )));
to get
Array
(
[0] => foo
[1] => foo20
[2] => foo02
[3] => foo39
[4] => foo91
)
Although as pointed out - sometimes a simple foreach() is just as good and sometimes better.

PHP multidimensional associative array [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 3 months ago.
I am new to php & I'm not sure that this can be done, but I am hoping that someone knows how to. I've collected all the data that I need to submit but now I need to reformat it before I can json_encode to send to the database.
Basically, I have 1 parent array($data) containing 3 sub-arrays ($hours, $WId, $Pid). I need to create associative arrays for each index position & join them together.
Here is my parent array:
$data = array(
'hours' => array(),
'wId' => array(),
'phaseId' => array(),
);
Here is what currently returns when I print_r each of these arrays:
Array ( [hours] => Array ( [0] => 0.5 [1] => 1 [2] => 2 ) )
Array ( [wId] => Array ( [0] => 10, [1] => 9, [2] => 8, ) )
Array ( [phaseId] => Array ( [0] => 20, [1] => 20, [2] => 19, ) )
I need to take these "vertical" arrays & turn them in to "horizontal" arrays per index, using thearray name as the $key & the value for that index as $value. Here is what I need to return.... (Syntax is probably wrong but you can get the idea.)
Array[1] ("hours" => 0.5, "wId" => 10, "phaseId" => 20)
Array[2] ("hours" => 1, "wId" => 9, "phaseId" => 20)
Array[3] ("hours" => 2, "wId" => 8, "phaseId" => 19)
Is there a function that will allow me to do this easily? I saw how to join & merge them together but not sure how to set the array name (hours, etc) as the $key & the value for each index as $value. I need to loop it too because the length of the arrays will vary. (But they will always the same length as each other, so index should still work as what needs to be collected.)
Any suggestions would be greatly appreciated :)
<?php
// set up your output array
$result = array();
// loop through $data, exposing $name for later use
foreach ($data as $name => $array) {
// loop through each named array and set the desired value
// using the current $key and $name
foreach ($array as $key => $value) {
$result[$key][$name] = $value;
}
}
// tada!
print_r($result);
NOTE: In your desired results in your question, you had the parent Array keys starting at 1. This answer assumes that's a typo and you actually wanted them to match the input. If you indeed wanted it to start at one, just change this line in my answer:
$result[$key+1][$name] = $value;

Group row data within a 2d array based on a single column and push unique data into respective subarrays

I need to group data in a multidimensional array data which can be related on a single column entry_id.
In addition to the entry_id there are other columns that will also be identical in other related rows (ic, name, and residency). While grouping, these data points can simply be overwritten -- in other words, I don't need to collect multiple copies of the same value within the respective group.
Finally, there will be data points within respective groups that will differ -- these values need to stored as subarrays within the groups so that no data is lost.
If there is only one row's data in a group, the file_no and detail data does not need to be converted to an array. This means that the result array will have variable depth -- some rows will flat and other may be 2 dimensional.
Sample input:
$array = [
[
'entry_id' => 1,
'ic' => 2147483647,
'name' => 'Kořínková Blanka',
'residency' => 'Štětí, Lukešova 354, 411 08',
'file_no' => 'KSUL 77 INS 18898 / 2013',
'detail' => '749371da-725c-4738-8def-2f7167142a6f'
],
[
'entry_id' => 1,
'ic' => 2147483647,
'name' => 'Kořínková Blanka',
'residency' => 'Štětí, Lukešova 354, 411 08',
'file_no' => 'KSUL 77 INS 21218 / 2013',
'detail' => '43b6a718-4647-451d-9c53-50dfee8403ff'
],
[
'entry_id' => 2,
'ic' => 46900217,
'name' => 'ENTEC a.s. "v likvidaci"',
'residency' => 'Staré Město, Brněnská 1916, 686 03',
'file_no' => 'KSBR 28 INS 1232 / 2013',
'detail' => 'e2155a52-c464-4357-b71b-4f4ff75585eb'
],
];
Desired output (based on same 'entry_id' grouping):
Array
(
[0] => Array
(
[entry_id] => 1
[ic] => 2147483647
[name] => Kořínková Blanka
[residency] => Štětí, Lukešova 354, 411 08
[file_no] => Array
(
[0] => KSUL 77 INS 18898 / 2013
[1] => KSUL 77 INS 21218 / 2013
)
[detail] => Array
(
[0] => A749371da-725c-4738-8def-2f7167142a6f
[1] => 43b6a718-4647-451d-9c53-50dfee8403ff
)
)
[1] => Array
(
[entry_id] => 2
[ic] => 46900217
[name] => ENTEC a.s. "v likvidaci"
[residency] => Staré Město, Brněnská 1916, 686 03
[file_no] => KSBR 28 INS 1232 / 2013
[detail] => e2155a52-c464-4357-b71b-4f4ff75585eb
)
)
Your issue can be resolved with one functional block, using array_reduce() and array_merge() principles:
$mergeId = 'entry_id';
$data = array_reduce($data, function($c, $x) use ($mergeId)
{
$c[$x[$mergeId]] = isset($c[$x[$mergeId]])
?array_combine(
$z=array_keys($c[$x[$mergeId]]),
array_map(function($y) use ($x, $c, $mergeId)
{
return in_array($x[$y], (array)$c[$x[$mergeId]][$y])
?$c[$x[$mergeId]][$y]
:array_merge((array)$c[$x[$mergeId]][$y], [$x[$y]]);
}, $z)
)
:$x;
return $c;
}, []);
you may want to apply array_values() if you need to re-index result set (so keys would be consecutive, starting from 0). Check the fiddle.
Using a nested loop to iterate a single array for potential matches is an indirect "brute force" technique -- there are some fringe cases where this can be tolerated, but in this case the more performant and professional approach will be to assign temporary first level keys as you iterate each row. The new associative arrays permit simple/swift searching because of the way that PHP handles arrays/keys.
When an entry_id value is encountered for the first time, simply save the whole row. When an entry_id value is encountered after the first time, the scalar-typed file_no and detail elements need to be converted to array-type . This can be done manually, but array_merge_recursive() offers this "magic" natively.
Call array_values() after finished iterating if you do not want to keep the first level grouping keys.
Code: (Demo)
$result = [];
foreach ($array as $row) {
if (!isset($result[$row['entry_id']])) {
$result[$row['entry_id']] = $row;
} else {
$result[$row['entry_id']] = array_merge_recursive(
$result[$row['entry_id']],
['file_no' => $row['file_no'], 'detail' => $row['detail']]
);
}
}
var_export(array_values($result));
Manually re-casting elements within groups (Demo)
$result = [];
foreach ($array as $row) {
if (!isset($result[$row['entry_id']])) {
$result[$row['entry_id']] = $row;
} else {
$result[$row['entry_id']]['file_no'] = (array) $result[$row['entry_id']]['file_no']; // re-cast as single-element array
$result[$row['entry_id']]['detail'] = (array) $result[$row['entry_id']]['detail']; // re-cast as single-element array
$result[$row['entry_id']]['file_no'][] = $row['file_no']; // push new element into subarray
$result[$row['entry_id']]['detail'][] = $row['detail']; // push new element into subarray
}
}
var_export(array_values($result));

php array remove key and shift values up

I've researched topics similar to this but not exactly what I'm looking to do.
I have a multidimensional array like the following.
[code] => BILL
[assets] => Array
(
[en] => Array
(
[datatype] => My Assets
[data] => Array
(
[Corporate Equity] => 41
[Global Equity] => 24
[Fixed Income – Government] => 22
[Fixed Income – Corporate] => 8.1
[Other] => 3.57
)
)
)
I'd like to remove the first inner array, but preserve the values. Shift them up one level in the array so that it looks like this.
[code] => BILL
[assets] => Array
(
[datatype] => My Assets
[data] => Array
(
[Corporate Equity] => 41
[Global Equity] => 24
[Fixed Income – Government] => 22
[Fixed Income – Corporate] => 8.1
[Other] => 3.57
)
)
This is just the beginning of the array, there are other instances of the same key [en] at the same level.
I've tried unset, array_shift and others but I need to keep the contents of [en], just shift them up one level in the array.
You can use array_map which returns an array which contains all elements of the previous array after applying the function.
In this case it will simply take the array at index en and add it's contents to the new array.
http://php.net/manual/en/function.array-map.php
$arr = array('assets' => array(
'en' => array(
'datatype' => 'My Assets',
'data' => array(
'Corporate Equity' => 41,
'Global Equity' => 24,
'Fixed Income – Government' => 22,
'Fixed Income – Corporate' => 8.1,
'Other' => 3.57
)
)
));
$new_arr = array_map(function ($e) {
return $e['en'];
}, $arr);
A simple solution that assumes the key to always be en and the subkeys to always be (only) datatype and data:
$assets['datatype'] = $assets['en']['datatype'];
$assets['data'] = $assets['en']['data'];
unset( $assets['en'] );
This code could be problematic for you in the future if that array structure ever changes (it lacks extensibility), but it gets you what you want given the information you have provided.
array_shift is the opposite of array_pop. Used in stack/queue like structures for removing the fist element http://php.net/manual/en/function.array-shift.php
What you want to do is flatten the array. But if you want to keep all the other sub-arrays as you mentioned, you might look up array_merge.
I faced the same scenario after using reader to read xml file, the returned array was having inserted 0 key array in each level like the following one:
'config' =>
0 =>
'products' =>
0 =>
'media' =>
.
.
.
so I built a small function to get rid of a specific key and shift up its child's in a two dimensions array, in my case the key was 0. hopping this would help somebody also.
public function clearMaps(&$maps, $readerMaps, $omittedKey)
{
if (is_array($readerMaps)) {
foreach ($readerMaps as $key => $map) {
if ($key !== $omittedKey) {
$maps[$key] = [];
$this->clearMaps($maps[$key], $readerMaps[$key], $omittedKey);
} else {
$this->clearMaps($maps, $readerMaps[$key], $omittedKey);
}
}
} else {
$maps = $readerMaps;
}
}
// $maps: cleaned array, will start as empty array
// $readerMaps: array needs to be cleaned
// $omittedKey: array key to git rid of.
// first call is clearMaps([], $readerMaps, 0);

Remove Values from PHP Array if Present

I have the following PHP array:
Array
(
[0] => 750
[1] => 563
[2] => 605
[3] => 598
[4] => 593
)
I need to perform the following action on the array using PHP:
Search the array for a value (the value will be in a
variable; let's call it $number). If the value
is present in the array, remove it.
If someone could walk me through how to do that, it would be much appreciated.
Note: If it makes it any easier, I can form the array so the keys are the same as the values.
$array = array_unique($array) // removes dupicate values
while(false !== ($num = array_search($num, $array))){
unset($array[$num]);
}
$max = max($array);
will search for all keys with value $num and unset them
lets say your $array
$array = array_unique($array) // removes dupicate values
$array = arsort($array)
$variable = $array[0] // the maximum value in the array, and place it in a variable.
$key = array_search($array, $number);
if($key){
unset($array[$key]) // Search array for a value, value is present in array, remove it.
}
array_search() and unset() seems a good method for your sample data in your question. I'll just show a different way for comparison's sake (or in case your use case is slightly different from what you have posted here).
Methods: (Demo)
$array=[750,563,605,598,593];
// if removing just one number apply the number as an array element
$number=605;
var_export(array_diff($array,[$number]));
// if you are performing this task with more than one $number, make $numbers=array() and do the same...
$numbers=[605,563]; // order doesn't matter
var_export(array_diff($array,$numbers));
// if you need to re-index the output array, use array_values()...
$numbers=[605,563]; // order doesn't matter
var_export(array_values(array_diff($array,$numbers)));
Output:
array (
0 => 750,
1 => 563,
3 => 598,
4 => 593,
)
array (
0 => 750,
3 => 598,
4 => 593,
)
array (
0 => 750,
1 => 598,
2 => 593,
)

Categories