Combine Indexed arrays with the same keys - php

I am using the Flot jQuery plugin to create a graph on how many visitors there have been per platform. I would like to create a 4th line with total visitors, calculated by previously retrieved data.
I need to combine several multi-dimensional Indexed arrays, but not simply merging them recursively. I.E:
$arr1 = [[2016/05/04,2],[2016/05/03,4],[2016/05/02,6]];
$arr2 = [[2016/05/04,1],[2016/05/03,3],[2016/05/02,2]];
$arr3 = [[2016/05/04,6],[2016/05/03,7],[2016/05/02,8]];
The output should be:
$arrTotal = [[2016/05/04,9],[2016/05/03,14],[2016/05/02,16]];
How do I accomplish this in a (fairly) simple way?

First of all, you cannot declare your dates the way you did:
$arr1 = [[2016/05/04,2],[2016/05/03,4],[2016/05/02,6]];
Because it's going to take 2016, divide it by 5 then divide it by 4. You need to put them into quotes.
$arr1 = [['2016/05/04',2],['2016/05/03',4],['2016/05/02',6]];
But to create an associative array, you should do it this way:
$arr1 = array('2016/05/04' => 2, '2016/05/03' => 4, '2016/05/02' => 6);
$arr2 = array('2016/05/04' => 1, '2016/05/03' => 3, '2016/05/02' => 2);
$arr3 = array('2016/05/04' => 6, '2016/05/03' => 7, '2016/05/02' => 8);
Now all you want to do, is loop through each array and sum them up.
$merge = array();
function mergeArray(Array &$merge, Array $array){
// Loop through each key and value
foreach($array as $key => $value)
// Make sure the value is numeric
if(is_numeric($value)){
if(!isset($merge[$key]))
$merge[$key] = $value;
else
$merge[$key] += $value;
}
}
mergeArray($merge, $arr1);
mergeArray($merge, $arr2);
mergeArray($merge, $arr3);
And now if you dump the $merge:
array(3) {
["2016/05/04"]=>
int(9)
["2016/05/03"]=>
int(14)
["2016/05/02"]=>
int(16)
}

Build a method that will sum the values by respecting the keys of existing values.
$arr1 = array('2016/05/04'=>2,'2016/05/03'=>4,'2016/05/02'=>6);
$arr2 = array('2016/05/04'=>1,'2016/05/03'=>3,'2016/05/02'=>2);
$arr3 = array('2016/05/04'=>2,'2016/05/03'=>7,'2016/05/02'=>8);
function array_sum(&$new_arr,$arr) {
foreach ($arr as $date_key => $num_value) {
// initialize date in new array with 0, if not done previously
if (! isset($new_arr[$date_key])) { $new_arr[$date_key] = 0; }
// add number for indexed element of array
$new_arr[$date_key] += $num_value;
}
}
$new_arr = array();
array_sum($new_array,$arr1);
array_sum($new_array,$arr2);
array_sum($new_array,$arr3);

You are trying to sum up every second value from each nested array relatively to their position in the parent array.There's a short and simple solution using array_map, array_sum and array_column functions:
$groupped = array_map(null, $arr1,$arr2,$arr3);
$result = array_map(function($v){
return [$v[0][0], array_sum(array_column($v, 1))];
}, $groupped);
print_r($result);
The output:
Array
(
[0] => Array
(
[0] => 2016/05/04
[1] => 9
)
[1] => Array
(
[0] => 2016/05/03
[1] => 14
)
[2] => Array
(
[0] => 2016/05/02
[1] => 16
)
)

Related

How can i split array into two array based on integer value

Here is an example array I want to split:
(1428,217,1428)
How do I split it in 2 array like this?
(1428,1428)
(217)
I have tried following way but it's only return 1428 array.
$counts = array_count_values($array);
$filtered = array_filter($array, function ($value) use ($counts) {
return $counts[$value] > 1;
});
One way to solve this for your example data is to sort the array and use array_shift to get the first element of the array and store that in an array.
$a = [1428,217,1428];
sort($a);
$b = [array_shift($a)];
print_r($a);
print_r($b);
Result
Array
(
[0] => 1428
[1] => 1428
)
Array
(
[0] => 217
)
You can try this.
$array = array(1428,217,1428);
$array1 = array_slice($array, 0, 2);
$array2 = array_slice($array, 2, 3);
print_r($array1);
print_r($array2);
And the output will like this:-
Array
(
[0] => 1428
[1] => 217
)
Array
(
[0] => 1428
)
In your case it will only return 1428 since array_count_values returns an array with values as keys and their frequency as array value therefore $counts will be equal to array('1428' => 2, '217' => 1);
If I understood your question well you should do something like this:
$array1 = [1428, 217, 1428];
$result = [];
foreach($array1 as $value){
$result[$value][] = $value;
}
This will not create an array for each different value but will create a new element for each unique value in $result. The final value of $result will be array('1428' => [1428, 1428], '217' => [217]) . Which can be easily manipulated as if they were 2 different arrays.
Let me know if this works for you, if not I will try to update my answer according to your specification.

Count how many times a value appears in this array?

I have this php array named $ids:
Array (
[0] => Array ( [id] => 10101101 )
[1] => Array ( [id] => 18581768 )
[2] => Array ( [id] => 55533322 )
[3] => Array ( [id] => 55533322 )
[4] => Array ( [id] => 64621412 )
)
And I need to make a new array containing each $ids id value, as the new keys, and the times each one appears, as the new values.
Something like this:
$newArr = array(
10101101 => 1,
18581768 => 1,
55533322 => 2,
64621412 => 1,
);
This is what I have:
$newArr = array();
$aux1 = "";
//$arr is the original array
for($i=0; $i<count($arr); $i++){
$val = $arr[$i]["id"];
if($val != $aux1){
$newArr[$val] = count(array_keys($arr, $val));
$aux1 = $val;
}
}
I supose array_keys doesn't work here because $arr has the id values in the second dimension.
So, how can I make this work?
Sorry for my bad english and thanks.
array_column will create an array of all the elements in a specific column of a 2-D array, and array_count_values will count the repetitions of each value in an array.
$newArr = array_count_values(array_column($ids, 'id'));
Or do it by hand like this where $arr is your source array and $sums is your result array.
$sums = array();
foreach($arr as $vv){
$v = $vv["id"];
If(!array_key_exists($v,$sums){
$sums[$v] = 0;
}
$sums[$v]++;
}
You can traverse your array, and sum the id appearance, live demo.
$counts = [];
foreach($array as $v)
{
#$counts[$v['id']] += 1;
}
print_r($counts);

Remove duplicates from a multi-dimensional array based on 2 values

I have an array that looks like this
$array = array(
array("John","Smith","1"),
array("Bob","Barker","2"),
array("Will","Smith","2"),
array("Will","Smith","4")
);
In the end I want the array to look like this
$array = array(
array("John","Smith","1"),
array("Bob","Barker","2"),
array("Will","Smith","2")
);
The array_unique with the SORT_REGULAR flag checks for all three value. I've seen some solutions on how to remove duplicates based on one value, but I need to compare the first two values for uniqueness.
Simple solution using foreach loop and array_values function:
$arr = array(
array("John","Smith","1"), array("Bob","Barker","2"),
array("Will","Smith","2"), array("Will","Smith","4")
);
$result = [];
foreach ($arr as $v) {
$k = $v[0] . $v[1]; // considering first 2 values as a unique key
if (!isset($result[$k])) $result[$k] = $v;
}
$result = array_values($result);
print_r($result);
The output:
Array
(
[0] => Array
(
[0] => John
[1] => Smith
[2] => 1
)
[1] => Array
(
[0] => Bob
[1] => Barker
[2] => 2
)
[2] => Array
(
[0] => Will
[1] => Smith
[2] => 2
)
)
Sample code with comments:
// array to store already existing values
$existsing = array();
// new array
$filtered = array();
foreach ($array as $item) {
// Unique key
$key = $item[0] . ' ' . $item[1];
// if key doesn't exists - add it and add item to $filtered
if (!isset($existsing[$key])) {
$existsing[$key] = 1;
$filtered[] = $item;
}
}
For fun. This will keep the last occurrence and eliminate the others:
$array = array_combine(array_map(function($v) { return $v[0].$v[1]; }, $array), $array);
Map the array and build a key from the first to entries of the sub array
Use the returned array as keys in the new array and original as the values
If you want to keep the first occurrence then just reverse the array before and after:
$array = array_reverse($array);
$array = array_reverse(array_combine(array_map(function($v) { return $v[0].$v[1]; },
$array), $array));

PHP: take out duplicate digits from an array then print them out

I'm probably [super]overthinking this. I'm trying to analyze an array with values like [1,9], [4,6] [5,5], [6,4], [9,1] and duplicate digits (I'm having a super brain fart and can't even remember the term for numbers like this) remove (the last two) so that only [1,9], [4,6] [5,5] are printed.
I was thinking that turning this array into a string and using preg_match, but I'm pretty sure this wouldn't work even if I had the correct regex.
If you have an array of pairs like this:
$x = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1)
);
Here is one way to get the unique pairs:
foreach ($x as $pair) {
sort($pair);
$unique_pairs[implode(',', $pair)] = $pair;
}
This uses string representations of each sorted pair as keys in a new array, so the result will have distinct values by definition.
As far as the printing them out part of your question, once you have the unique values you can loop over them and print them out in whichever format you like, for example:
foreach ($unique_pairs as $pair) { vprintf("[%d,%d]<br>", $pair); }
It looks like elements are distributed symmetrically.
We can cut the array in two halves and get only the first half with array_slice():
$array = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 4
[1] => 6
)
[2] => Array(
[0] => 5
[1] => 5
)
)
Demo at Codepad.
ceil() is used to round the number up to the next highest integer if there is an even number of items in the array. Example: if there is 3 items in the array, 5 / 2 will return 2.5, we want 3 items so we use ceil(2.5) which gives 3.
Example with 3 items:
$array = array(
array(1,9),
array(5,5),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 5
[1] => 5
)
)
Example with 4 items:
$array = array(
array(1,9),
array(7,7),
array(7,7),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 7
[1] => 7
)
)
If I'm correct in understanding what you are trying to do, you want to remove the final 2 elements from the array?
There is a function in PHP called array_pop that removes the final element from the array.
$array = array_pop($array);
So if you run this twice, you will remove the final 2 elements from the array.
This is how I'd do it (and I hope I am not overthinking this :))
$stringArray = array();
$stringArray[] = '1,9';
$stringArray[] = '4,6';
$stringArray[] = '5,5';
$stringArray[] = '6,4';
$stringArray[] = '9,1';
foreach($stringArray as &$numString) {
$numString = explode(',', $numString);
usort($numString, function($a, $b) {return $a - $b;});
$numString = implode(',', $numString);
}
$a = array_unique($a);
print_r($a);
You basically explode every element into a subarray, sort it and then implode it back. After calling the array_unique, you're left with unique values in the array.
The output would be
Array
(
[0] => 1,9
[1] => 4,6
[2] => 5,5
)
The result you suggest treats [a,b] as equivalent to [b,a] which makes the problem a lot more complex. The code below gives the result you asked for, but without really understanding what the problem is that you are trying to fix and whether [1,9] is equivalent to [9,1] in the solution:
$a=array(array(1,9),array(4,6),...
$dup=array();
for ($i=0; $i<count($a) -1; $i++) {
for ($j=$i+1; $j<count($a); $j++) {
if (($a[$i][0]==$a[$j[0] && $a[$i][1]==$a[$j[1])
|| ($a[$i][0]==$a[$j[1] && $a[$i][1]==$a[$j[0])) {
$dup[]=$j;
}
}
}
foreach ($dup as $i) {
unset($a[$i]);
}
So I'm actually going to assume your question to have a different meaning than everyone else did. I believe what you're asking is:
How do you filter out array items where a reverse of the item has already been used?
<?php
// The example set you gave
$numberSets = [[1, 9], [4, 6], [5, 5], [6, 4], [9, 1]];
// Initialize an empty array to keep track of what we've seen
$keys = [];
// We use array filter to get rid of items we don't want
// (Notice that we use & on $keys, so that we can update the variable in the global scope)
$numberSets = array_filter($numberSets, function($set) use(&$keys) {
// Reverse the array
$set = array_reverse($set);
// Create a string of the items
$key = implode('', $set);
// Get the reverse of the numbers
$reversedKey = strrev($key);
// If the palindrome of our string was used, return false to filter
if (isset($keys[$reversedKey])) {
return false;
}
// Set the key so it's not used again
// Since $keys is being passed by reference it is updated in global scope
$keys[$key] = true;
// Return true to NOT filter this item, since it or it's reverse were not matched
return true;
});
var_dump($numberSets);

Multidimenssion array compare two arrays and update first array value

I want to filter a array by a number and update its status in the first array.
I have two array $arr1,$arr2
$arr1 = array(
0=>array('number'=>100,name=>'john'),
1=>array('number'=>200,name=>'johnny')
);
$arr2= array(
0=>array('number'=>300,name=>'r'),
1=>array('number'=>100,name=>'b'),
2=>array('number'=>200,name=>'c')
);
Final output should be an array like this
$arr1 = array(
0=>array('number'=>100,name=>'b'),
1=>array('number'=>200,name=>'c')
);
Any ideas to start off please ?
For specialized array modifications like this, the method of choice is array walk. It allows you to apply a custom function to each element in a given array.
Now, because of your data format, you will have to do a loop. Wrikken is asking if you can retrieve or transform the data to provide faster access. The algorithm below is O(n^2): it will require as many cycles as there are elements in the first array times the number of elements in the second array, or exactly count($arr1) * count($arr2).
function updateNameFromArray($element, $key, $arr2) {
foreach($arr2 as $value) {
if($value['number'] == $element['number']) {
$element['name'] == $value['name'];
break;
}
}
}
array_walk($arr1, "updateNameFromArray", $arr2);
Now, what Wrikken is suggesting is that if your arrays can be changed to be keyed on the 'number' property instead, then the search/replace operation is much easier. So if this were your data instead:
$arr1 = array(
100=>array('number'=>100,name=>'john'),
200=>array('number'=>200,name=>'johnny')
);
// notice the keys are 100 and 200 instead of 0,1
$arr2= array(
300=>array('number'=>300,name=>'r'),
100=>array('number'=>100,name=>'b'),
200=>array('number'=>200,name=>'c')
);
// notice the keys are 300, 100 and 200 instead of 0,1, 2
Then you could do this in O(n) time, with only looping over the first array.
foreach($arr1 as $key => $value) {
if(isset($arr2[$key])) {
$value['number'] = $arr2[$key]['number'];
}
}
Try this. It's not that clean but i think it would work.
<?php
$arr1 = array(0=>array('number'=>100,'name'=>'john'),1=>array('number'=>200,'name'=>'johnny'));
$arr2= array(0=>array('number'=>300,'name'=>'r'),1=>array('number'=>100,'name'=>'b'),2=>array('number'=>200,'name'=>'c'));
foreach( $arr1 as $key=>$data1 )
{
foreach( $arr2 as $key2=>$data2 )
{
if( $data1['number'] == $data2['number'] )
{
$arr1[$key]['name'] = $arr2[$key2]['name'];
}
}
}
print_r( $arr1 );
?>
the output would be :
Array
(
[0] => Array
(
[number] => 100
[name] => b
)
[1] => Array
(
[number] => 200
[name] => c
)
)
There isn't really a simple way for this to be accomplished with generic PHP functions, so, You might need to create mapping arrays.
The way I would approach this, is creating a loop that goes through the first array, and maps the number value as a key to the index of it's place in $arr1 giving you:
$tmp1 = array();
foreach ($arr1 as $key => $number_name) {
$tmp1[$number_name['number']] = $key;
}
This should give you an array that looks like
$tmp1 [
100 => 0,
200 => 1
];
Then I would loop through the second array, get the number value, if that existed as a key in $tmp1, get the associated value (being the key for $arr1), and use that to update the name in $arr1.
// Loop through $arr2
foreach ($arr2 as $number_name) {
// Get the number value
$number = $number_name['number'];
// Find the $arr1 index
if (isset($tmp1[$number])) {
$arr1_key = $tmp1[$number];
// Set the $arr1 name value
$arr1[$arr1_key]['name'] = $number_name['name'];
}
}
<?php
//Set the arrays
$arr1 = array(
array('number'=>100,'name'=>'john'),
array('number'=>200,'name'=>'johnny')
);
$arr2= array(
array('number'=>300,'name'=>'r'),
array('number'=>100,'name'=>'b'),
array('number'=>200,'name'=>'c')
);
// use a nested for loop to iterate and compare both arrays
for ($i=0;$i<count($arr1);$i++):
for ($j=0;$j<count($arr2);$j++):
if ($arr2[$j]['number']==$arr1[$i]['number'])
$arr1[$i]['name']=$arr2[$j]['name'];
endfor;
endfor;
print_r($arr1);
OUTPUT:
Array (
[0] => Array ( [number] => 100 [name] => b )
[1] => Array ( [number] => 200 [name] => c )
)
That being said, you should probably reconsider the very way your data is structured. Do you really need a multi-dimensional array or can you use a simple associative array, like so:
// set the arrays
$arr1 = array(
'john'=>100,
'johnny'=>200
);
$arr2 = array(
'r'=>300,
'b'=>100,
'c'=>200
);
// find values in arr2 common to both arrays
$arr3 = array_intersect($arr2, $arr1);
// change the key of arr1 to match the corresponding key in arr2
foreach ($arr3 as $key=>$value) {
$old_key = array_search($value, $arr1);
$arr1[$key]=$arr1[$old_key];
unset($arr1[$old_key]);
}
print_r($arr1);
OUTPUT:
Array (
[b] => 100
[c] => 200
)

Categories