Count and remove duplicate arrays - php

I'm trying to count and remove duplicate arrays. To be a duplicate the entire array would have the match in keys and values with another.
Array
(
[0] => Array
(
[name] => Superman
[time] => 60
)
[1] => Array
(
[name] => Superman
[time] => 60
)
[2] => Array
(
[name] => Superman
[time] => 50
)
[3] => Array
(
[name] => Superman
[time] => 40
)
[4] => Array
(
[name] => Superman
[time] => 50
)
[5] => Array
(
[name] => Superman
[time] => 60
)
)
Into:
Array
(
[0] => Array
(
[name] => Superman
[time] => 60
[count] => 3
)
[1] => Array
(
[name] => Superman
[time] => 50
[count] => 2
)
[2] => Array
(
[name] => Superman
[time] => 40
)
)
I've come across this answer that can remove the duplicates, but I'm struggling to see how I may count them.
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

Quick and dirty, but you get exactly the data structure you asked for:
$data = array(
array("name" => "Superman", "time" => 60),
array("name" => "Superman", "time" => 60),
array("name" => "Superman", "time" => 50),
array("name" => "Superman", "time" => 40),
array("name" => "Superman", "time" => 50),
array("name" => "Superman", "time" => 60),
);
// count the occurrences
$occurrences = array();
for ($i = 0, $l = count($data); $i < $l; $i++) {
$serialized = serialize($data[$i]);
if (!isset($occurrences[$serialized])) {
$occurrences[$serialized] = 1;
}
else {
$occurrences[$serialized] = $occurrences[$serialized] + 1;
}
}
// get the wanted structure
$uniques = array();
foreach ($occurrences as $serialized => $count) {
$unserialized = unserialize($serialized);
if ($count > 1) {
$unserialized['count'] = $count;
}
$uniques[] = $unserialized;
}
print_r($uniques);

Not as compact as I would like, but it gets the job done:
function unserialize_unique_count($input, $k = 'count') {
$a = [];
foreach ($input as $d) {
$s = serialize($d);
$a[$s] = (isset($a[$s]) ? ($a[$s] + 1) : 1);
}
foreach ($a as $s => $c) {
$a[$s] = unserialize($s) + [ $k => $c ];
}
return array_values($a);
}
$grouped_with_count = unserialize_unique_count($input);
How it works: The first loop serializes and counts. The second unique merges. O(n).
How to use: Pass your multi-dimensional array as argument #1. Gives you back uniques with an additional key "count" that holds the count. If you want the count key to be something other than "count", pass the function a second argument.

You can use array_count_values in this case too. Example:
$values = array(
array('name' => 'Superman', 'time' => 60),
array('name' => 'Superman', 'time' => 60),
array('name' => 'Superman', 'time' => 50),
array('name' => 'Superman', 'time' => 40),
array('name' => 'Superman', 'time' => 50),
array('name' => 'Superman', 'time' => 60),
);
// map out into string then unique them
$uniques = array_map("unserialize", array_unique(array_map("serialize", $values)));
$count = array_count_values(array_map("serialize", $values)); // map out the arrays then get the counts
// then to merge the count
foreach($uniques as &$batch) {
foreach($count as $array => $v) {
if(unserialize($array) == $batch) { // if this particular key count is equal to this unique array, then push the count
$batch['count'] = $v;
}
}
}
echo '<pre>';
print_r($uniques);
Sample Output

Get Array and its values
make unique key on paypal_address
Use unique key to create temp array
Store all values with respective unique key in temp array
I am using time as unique key.
$tmpArr = Array();
$cnt = sizeof($arr);
for($i=0;$i<$cnt;$i++){
$time = $arr[$i]['time'];
if(!is_array($tmpArr[$time])){
$tmpArr[$time] = Array();
$tmpArr[$time]['count'] = 0;
}
$tmpArr[$time]['time'] = $arr[$i]['time'];
$tmpArr[$time]['name'] = $arr[$i]['name'];
$tmpArr[$time]['count'] = $tmpArr[$time]['count'] + 1;
}
print_r($tmpArr);
Note: Make changes in code according to your requirement

Related

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
)
)

Merge arrays in an array and add values

I need to take an array like this:
Array
(
[0] => Array
(
[county_code] => 54045
[count] => 218
)
[1] => Array
(
[county_code] => 54045
[count] => 115
)
[2] => Array
(
[county_code] => 54051
[count] => 79
)
)
And merge all arrays with the same county_code adding the count, like this:
Array
(
[0] => Array
(
[county_code] => 54045
[count] => 333
)
[1] => Array
(
[county_code] => 54051
[count] => 79
)
)
There will be multiple instances of multiple county codes.
Can anyone point me in the right direction?
Try this out:
// your example array
$array = [
[
"county_code" => 54045,
"count" => 218
],
[
"county_code" => 54045,
"count" => 115
],
[
"county_code" => 54051,
"count" => 79
]
];
// intrim step to collect the count.
$intrimArray = [];
foreach( $array as $data ){
$countyCode = $data["county_code"];
if (!$intrimArray[$countyCode]) {
$intrimArray[$countyCode] = $data["count"];
} else {
$intrimArray[$countyCode] = $intrimArray[$countyCode] + $data["count"];
}
}
// build the final desired array using interim array.
$finalArray = [];
foreach($intrimArray as $countyCode => $totalCount) {
array_push($finalArray, [
"county_code" => $countyCode,
"count" => $totalCount
]);
}
var_dump($finalArray);
As promised:
<?php
$initial_array = [
['country_code' => 54045, 'count' => 218],
['country_code' => 54045, 'count' => 115],
['country_code' => 54051, 'count' => 79],
];
$synth = [];
foreach ($initial_array as $sa) { # $sa: subarray
if (!isset($synth[$sa['country_code']])) {
$synth[$sa['country_code']] = 0;
}
$synth[$sa['country_code']] += $sa['count'];
}
print_r($synth); # Synthesis array: keys are country codes, values are cumulative counts.
# If you need the same format for both the initial and synthesis arrays, then continue with this:
$synth2 = [];
foreach ($synth as $k => $v) {
$synth2[] = ['country_code' => $k, 'count' => $v];
}
print_r($synth2);
?>
A fiddle for this code: https://3v4l.org/M8tkb
Best regards

How to merge an array with child elements

I have an array with same customerid. I want to merge all same customerid arrays in to one with few amends to the array.
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[customerid] => 1
[customer_fullname] => John
[profession_id] => 8
[profession_name] => Producer
)
[2] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 7
[profession_name] => Camera
)
)
So now I want a new array to be created like this:
Array(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => array(
[0]=>[profession_id] => 8, [profession_name] => Producer,
[1]=>[profession_id] => 7, [profession_name] => Camera
)
)
Spent some time on it but wasn't able to get it right
There are better approaches if you're merging lots of records, but if you want a way to just merge two records as stated, I'd just do this:
$array1 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 8,
'profession_name' => 'Producer'
);
$array2 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 7,
'profession_name' => 'Director'
);
function merge_customers($customerA, $customerB)
{
$newCustomer = array();
if ($customerA['customerid'] == $customerB['customerid'])
{
$newCustomer['customerid'] = $customerA['customerid'];
$newCustomer['customer_fullname'] = $customerA['customer_fullname'];
$newCustomer['new_array'] = array(
array(
'profession_id' => $customerA['profession_id'],
'profession_name' => $customerA['profession_name']
),
array(
'profession_id' => $customerB['profession_id'],
'profession_name' => $customerB['profession_name']
)
);
return $newCustomer;
}
/* We can't merge these if they're different customers. */
return NULL;
}
The extended solution which is also well-suited for finding and "merging" multiple groups of entries which has same customerid. Used functions: array_filter, array_count_values, array_keys, array_walk, array_chunk and array_values:
// supposing $arr is your initial array
// finds which 'customerid' has multiple entries
$dupIds = array_filter(array_count_values(array_column($arr, "customerid")), function($v) {
return $v > 1;
});
$dupIds = array_keys($dupIds);
$result = [];
array_walk($arr, function($v) use(&$result, $dupIds) {
if (in_array($v['customerid'], $dupIds)) {
$parts = array_chunk($v, 2, true);
if (!isset($result[$v['customerid']])) {
$result[$v['customerid']] = $parts[0] + ['new_array' => [$parts[1]]];
} else {
$result[$v['customerid']]['new_array'][] = $parts[1];
}
}
});
print_r(array_values($result));
The output:
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => Array
(
[0] => Array
(
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[profession_id] => 7
[profession_name] => Camera
)
)
)
)
Quick hack, maybe there is a nicer solution.
Note: The second "for each" loop is only needed if there is the possibility that the arrays don't have the same fields.
function merge($array1, $array2){
$result = array();
foreach($array1 as $key => $value){
if(isset($array2[$key]) && $array2[$key]!=$array1[$key]){
$result[$key][]=$value;
$result[$key][]=$array2[$key];
}else{
$result[$key]=$value;
}
}
foreach($array2 as $key => $value){
if(!isset($result[$key])){
$result[$key] = $value;
}
}
return $result;
}
print_r(merge($array1, $array2));

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
)

merge two keys on different identical keys in a multidimensional array

I have a single multidimensional array that I'm trying to merge keys. I'd like to merge where identical keys occur on a separate key from the one I'm trying to merge.
My current array looks like so.
Array
(
[0] => Array
(
[zone_id] => 2
[zone_title] => Users
[link_title] => Users
)
[1] => Array
(
[zone_id] => 2
[zone_title] => Users
[link_title] => Add User
)
[2] => Array
(
[zone_id] => 3
[zone_title] => Locations
[link_title] =>
)
)
I would like to leave the array as is with the exception of merging together arrays that have identical zone_id keys.
Result
Array
(
[0] => Array
(
[zone_id] => 2
[zone_title] => Users
[link_title] => Array
(
[0] => Users
[1] => Add user
)
)
[1] => Array
(
[zone_id] => 3
[zone_title] => Locations
[link_title] =>
)
)
<?php
function merge_keys($arr){
for ($key = 0; $key < count($arr); $key++) {
$zone_id = $arr[$key]['zone_id'];
$index = search($arr, $zone_id);
if ($index != $key && $index != -1){
$link_title = $arr[$key]['link_title'];
$link_title2 = $arr[$index]['link_title'];
$arr[$key]['zone_id'] = $zone_id;
$arr[$key]['zone_title'] = $arr[$key]['zone_title'];
$arr[$key]['link_title'] = array($link_title, $link_title2);
unset($arr[$index]);
}
}
return $arr;
}
function search($arr, $zone_id){
for ($i = count($arr) - 1; $i >= 0 ; $i--) {
$item = $arr[$i];
$tmp_zone_id = $item['zone_id'];
if($tmp_zone_id == $zone_id){
return $i;
}
}
return -1;
}
$arr = array(array('zone_id' => 2, 'zone_title' => 'Users', 'link_title' => 'Users'),
array('zone_id' => 2, 'zone_title' => 'Users', 'link_title' => 'Add User'),
array('zone_id' => 3, 'zone_title' => 'Locations', 'link_title' => ''));
echo "Before change: \n";
print_r($arr);
$arr = merge_keys($arr);
echo "After change: \n\n";
print_r($arr);
?>

Categories