Remove duplicate pair of values in an array - php

I have an array with the following structure:
[0] => Array
(
[venue1] => 1
[venue2] => 2
)
[1] => Array
(
[venue1] => 3
[venue2] => 4
)
[2] => Array
(
[venue1] => 2
[venue2] => 1
)
[3] => Array
(
[venue1] => 5
[venue2] => 6
)
I need to remove the duplicate "pair of values", in this case row [0] and row [2]
I tried it with that code, but it doesn't work (and of course it's not very elegant) ;-)
foreach ( $compare_arr as $v1 )
{
$key = array_search( intval($v1[venue1]), array_column( $compare_arr, 'venue2' ) );
if ( $key <> '' ) unset($compare_arr[$key]);
}
Do you have an idea how to solve this?
Thanks a lot for your help!
Oliver

Here is an approach where an intermediate array is formed of sorted values. That you can then search for to find duplicate pairs to remove.
<?php
$venues =
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 2,
'venue2' => 1,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
);
$result = $pairs = $venues;
array_walk($pairs, 'sort');
var_export($pairs);
foreach($pairs as $k => $pair) {
if(count(array_keys($pairs, $pair)) > 1) {
unset($result[$k]);
}
}
var_export($result);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
),
1 =>
array (
0 => 3,
1 => 4,
),
2 =>
array (
0 => 1,
1 => 2,
),
3 =>
array (
0 => 5,
1 => 6,
),
)array (
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
If you want to remove occurring duplicates rather than pruning out duplicates altogether, you can do an array_unique on the sorted array above and then use the remaining keys to filter the original array.
$tmp = $venues;
array_walk($tmp, 'sort');
$tmp = array_unique($tmp, SORT_REGULAR);
$result = array_intersect_key($venues, $tmp);
var_export($result);
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)

You might also first loop the array creating a compound key based on the ordered keys.
Then you can filter the result only keeping arrays where the count is 2 as nothing is added because there are no duplicates.
For example
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6],
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
$result[$cKey][] = $v1;
continue;
}
$result[$cKey] = $v1;
}
$result = array_filter($result, function($item) {
return count($item) === 2;
});
print_r($result);
Output
Array
(
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
You can see the compound keys are the values with a - in between. If you want to have the keys numbered from 0, you can use array_values.
Php demo
Edit
If you want to keep the first matching single pair, you can check for the compound key and if it already exists continue the loop without overwriting the existing one.
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6]
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
continue;
}
$result[$cKey] = $v1;
}
print_r($result);
Output
Array
(
[1-2] => Array
(
[0] => 1
[1] => 2
)
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
Php demo

Whether you use a classic foreach() loop or functional iteration, there is no reason to iterate the input array more than once.
This snippet will appear nearly identical to TheFourthBird's answer, but I don't like the unnecessary use of continue. This snippet will ensure no that rows in the result array have 100% shared venue values (in any order). The subarray keys will also not suffer reordering; in other words the first element key will be venue1 then the second element will be venue2. Using implode() offers additional flexibility because the code won't need to be altered if the number of elements in each row changes.
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($result[$key])) {
$result[$key] = $data[$index];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
To completely remove all rows where venue values are shared, maintain a "found" array as well as a "result" array.
Code: (Demo)
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($found[$key])) {
$found[$key] = true;
$result[$key] = $data[$index];
} else {
unset($result[$key]);
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 3,
'venue2' => 4,
),
1 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)

Related

want to add multidimensional array in php

I have two multi dimensional array.If the key is same then i want to get the sum how do i do that.
one is-
Array
(
[2018-08-02] => Array
(
[male] => 1
[female] => 0
)
[2018-08-07] => Array
(
[male] => 1
[female] => 0
)
[2018-08-09] => Array
(
[male] => 1
[female] => 5
)
)
2nd one is-
one is-
Array
(
[2018-08-02] => Array
(
[male] => 3
[female] => 4
)
[2018-08-07] => Array
(
[male] => 1
[female] => 5
)
[2018-08-06] => Array
(
[male] => 2
[female] => 3
)
)
so my result would be
Array
(
[2018-08-02] => Array
(
[male] => 4
[female] => 4
)
[2018-08-07] => Array
(
[male] => 2
[female] => 5
)
[2018-08-09] => Array
(
[male] => 1
[female] => 5
)
[2018-08-06] => Array
(
[male] => 2
[female] => 3
)
)
Code is
foreach ($reportlist as $reportlists){
$daterep=$reportlists['act_date'];
$arr[$daterep]['male']=$reportlists['male_cnt'];
$arr[$daterep]['female']=$reportlists['female_cnt'];
}
foreach ($ureportlist as $ureportlists){
$daterep=$rueportlists['act_date'];
$arr2[$daterep]['male']=$reportlists['male_cnt'];
$arr2[$daterep]['female']=$reportlists['female_cnt'];
}
Here is your code,
<?php
function pr($arr = [])
{
echo "<pre>";
print_r($arr);
echo "</pre>";
}
$arr1 = array
(
"2018-08-02" => array
(
"male" => 1,
"female" => 0,
),
"2018-08-07" => array
(
"male" => 1,
"female" => 0,
),
"2018-08-09" => array
(
"male" => 1,
"female" => 5,
),
);
$arr2 = array
(
"2018-08-02" => array
(
"male" => 3,
"female" => 4,
),
"2018-08-07" => array
(
"male" => 1,
"female" => 5,
),
"2018-08-06" => array
(
"male" => 2,
"female" => 3,
),
);
function custom_function($arr){
$retArr = array();
foreach ($arr as $child) { // arr1, arr2
foreach ($child as $key => $value) { // traversing through keys
foreach($value as $k => $v){
if (isset($retArr[$key][$k])) { // if key is set then add
$retArr[$key][$k] += $v;
} else {
$retArr[$key][$k] = $v; // else initiate
}
}
}
}
return $retArr;
}
$result=custom_function(array($arr1,$arr2));
pr($result);die;
Here is your working code
You can use array_intersect_key() to check if there is a matching results to add them.
for example, Let's assume your two arrays are $array1 and $array2. Then you can use
$result = array_intersect_key($array1, $array2);
This will return intersection in an array. So you can identify which keys have (in your case, which dates) need to be add.
You can use array_merge_recursive to join arrrays and then sum sub-arrays in the result array
$res = array_merge_recursive($arr1, $arr2);
foreach($res as &$date) {
foreach($date as &$sex) {
$sex = array_sum((array) $sex);
}
}
print_r($res);
demo
You simply need to iterate the 2nd array and determine whether or not the date keys exist in the 1st array. isset() is the best / most efficient way to run that check.
If a date from the 2nd array does not yet exist in the first, you can simply store the row's data to the 1st array. If the date already exists in the 1st array, then you will need to add (individually) the male and female values.
Code: (Demo)
$array1 = [
'2018-08-02' => ['male' => 1, 'female' => 0],
'2018-08-07' => ['male' => 1, 'female' => 0],
'2018-08-09' => ['male' => 1, 'female' => 5]
];
$array2 = [
'2018-08-02' => ['male' => 3, 'female' => 4],
'2018-08-07' => ['male' => 1, 'female' => 5],
'2018-08-06' => ['male' => 2, 'female' => 3]
];
foreach ($array2 as $date => $row) {
if (!isset($array1[$date])) {
$array1[$date] = $row; // store row data with unique date
} else {
$array1[$date]['male'] += $row['male']; // perform addition
$array1[$date]['female'] += $row['female']; // perform addition
}
}
// ksort($array1); if you want to order by date
var_export($array1);
Output:
array (
'2018-08-02' =>
array (
'male' => 4,
'female' => 4,
),
'2018-08-07' =>
array (
'male' => 2,
'female' => 5,
),
'2018-08-09' =>
array (
'male' => 1,
'female' => 5,
),
'2018-08-06' =>
array (
'male' => 2,
'female' => 3,
),
)

PHP Merge arrays and add a value

I need help merging two PHP arrays:
Array 1:
Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 6
)
Array 2:
Array
(
[0] => Array
(
[id_sabor] => 2
[chocolate] => N
)
[1] => Array
(
[id_sabor] => 3
[chocolate] => S
)
[2] => Array
(
[id_sabor] => 4
[chocolate] => N
)
[3] => Array
(
[id_sabor] => 5
[chocolate] => S
)
[4] => Array
(
[id_sabor] => 6
[chocolate] => N
)
)
The values on array 1 are the active objects. I need to keep on Array 2 or on a new array only the ones with an [id_sabor] that matches in the array 1 (in this case: 2, 3, 4 and 6). Also, on those that [chocolate]=S add a new value: [costo_extra]=25.
One way to do that could be to use array_reduce and use in_array to check if the first array contains the value of id_sabor.
$array1 = [2, 3, 4, 6];
$array2 = [
["id_sabor" => 1, "chocolate" => "N"],
["id_sabor" => 2, "chocolate" => "N"],
["id_sabor" => 3, "chocolate" => "S"],
["id_sabor" => 4, "chocolate" => "N"],
["id_sabor" => 5, "chocolate" => "S"],
["id_sabor" => 6, "chocolate" => "N"]
];
$array2 = array_reduce($array2, function($carry, $item) use ($array1){
if (in_array($item["id_sabor"], $array1)) {
if ($item["chocolate"] === "S") {
$item["costo_extra"] = 25;
}
$carry[] = $item;
}
return $carry;
});
Demo

How to group subarrays and perform conditional calculations?

I need to group my subarray using product_id and perform some conditional arithmetic.
If moving_type is 1 then the overall product_number tally for the current product_id should be increased by the product_number. Alternatively, if the moving_type is 2 then the overall product_number tally should be decreased by the product_number value.
This is my input array:
Array
(
[0] => Array
(
[id] => 1
[product_id] => 4
[product_number] => 10
[moving_type] => 1
)
[1] => Array
(
[id] => 1
[product_id] => 5
[product_number] => 10
[moving_type] => 1 // product addition
)
[2] => Array
(
[id] => 1
[product_id] => 5
[product_number] => 2
[moving_type] => 2 // product minus
)
)
My desired result is:
Array
(
[0] => Array
(
[id] => 1
[product_id] => 4
[product_number] => 10
)
[1] => Array
(
[id] => 1
[product_id] => 5
[product_number] => 8 // as 10-2
)
)
Most efficiently use temporary keys based on product_id to determine if you are performing arithmetic between two values or merely declaring the first occurring value for the product_id.
If it is the first occurrence, just slice the first three rows off the row and preserve the keys (that's the true part).
If it is not the first occurrence of product_id, then you will only need to update the product_number element. Determine the correct operation based on the moving_type value -- using that, multiply the product_number by either 1 or -1 and add that generated value to the stored value.
When the loop is finished, you can reindex the resulting array with array_values().
Code: (Demo)
$array = [
['id' => 1, 'product_id' => 4, 'product_number' => 10, 'moving_type' => 1],
['id' => 1, 'product_id' => 5, 'product_number' => 10, 'moving_type' => 1],
['id' => 1, 'product_id' => 5, 'product_number' => 2, 'moving_type' => 2]
];
foreach ($array as $row) {
if (!isset($result[$row['product_id']])) {
$result[$row['product_id']] = array_slice($row, 0, 3, true);
} else {
$result[$row['product_id']]['product_number'] += ($row['moving_type'] == 1 ? 1 : -1) * $row['product_number'];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'id' => 1,
'product_id' => 4,
'product_number' => 10,
),
1 =>
array (
'id' => 1,
'product_id' => 5,
'product_number' => 8,
),
)
You could use a foreach() loop. Inside it, you could create a new array using product_id as key. You could use *=-1 to change the sign of the product_number, and if the key already exists, add the current product_number to the existing one.
$array = array(
array('id' => 1, 'product_id' => 4, 'product_number' => 10, 'moving_type' => 1),
array('id' => 1, 'product_id' => 5, 'product_number' => 10, 'moving_type' => 1),
array('id' => 1, 'product_id' => 5, 'product_number' => 2, 'moving_type' => 2)
);
$final = [];
foreach ($array as $item) {
$pid = $item['product_id'] ;
if ($item['moving_type'] == 2) $item['product_number'] *= -1;
unset($item['moving_type']);
if (!isset($final[$pid])) { $final[$pid] = $item ; }
else {
$final[$pid]['product_number'] += $item['product_number'] ;
}
}
$final = array_values($final);
print_r($final);
Output:
Array
(
[0] => Array
(
[id] => 1
[product_id] => 4
[product_number] => 10
)
[1] => Array
(
[id] => 1
[product_id] => 5
[product_number] => 8
)
)

Removing items from an array based on items in another array

I have 2 arrays:
Array ( [0] => Array ( [intTrackId] => 41 [intAverageRating] => 10 [bolNewRelease] => 0 [dtDateAdded] => 2013-03-08 17:32:26 ) [1] => Array ( [intTrackId] => 1 [intAverageRating] => 7 [bolNewRelease] => 0 [dtDateAdded] => 2013-03-08 18:54:35 ))
Array ( [0] => Array ( [intTrackId] => 41 [intAverageRating] => 5.5000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ) [1] => Array ( [intTrackId] => 361 [intAverageRating] => 8.0000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ))
I want to remove the items in the second which have a matching track ID in the first. So in this example, I would get:
Array ( [0] => Array ( [intTrackId] => 361 [intAverageRating] => 8.0000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ))
Is this possible with array_filter or is this a little complex for that?
Just use array_udiff() - it's intended to do this:
$one = Array (
0 => Array ('intTrackId' => 41, 'intAverageRating' => 10, 'bolNewRelease' => 0, 'dtDateAdded' => '2013-03-08 17:32:26' ),
1 => Array ('intTrackId' => 1, 'intAverageRating' => 7, 'bolNewRelease' => 0, 'dtDateAdded' => '2013-03-08 18:54:35' )
);
$two = Array (
0 => Array ('intTrackId' => 41, 'intAverageRating' => 5.5000, 'bolNewRelease' => 1, 'dtDateAdded' => '2014-03-25T09:39:28Q' ),
1 => Array ('intTrackId' => 361, 'intAverageRating' => 8.0000, 'bolNewRelease' => 1, 'dtDateAdded' => '2014-03-25T09:39:28Q' )
);
$result = array_udiff($two, $one, function($x, $y)
{
return $x['intTrackId']-$y['intTrackId'];
});
Yes it can be done with array_filter:
$array1 = array(...);
$array2 = array(...);
$newArray = array_filter($array2, function($item) use ($array1){
foreach($array1 as $elem){
if($item['intTrackId'] == $elem['intTrackId']){
return false;
}
}
return true;
});
I would first create a loop and store all track IDs from the first array in a separate array.
Then I'd loop over the second array and delete those keys that exist in the track ID array.
$track_ids = array();
foreach($array1 as $index => $items) {
$track_ids[$items['intTrackId']] = $index;
}
foreach($array2 as $items) {
if (isset($track_ids[$items['intTrackId']])) {
unset($array2[$track_ids[$items['intTrackId']]]);
}
}

Merge two multidimensional arrays and reindex all subarrays

I have two arrays, I want to merge these two arrays into single array. Please view the detail below:
First Array:
Array
(
[0] => Array
(
[a] => 1
[b] => 2
[c] => 3
)
[1] => Array
(
[a] => 3
[b] => 2
[c] => 1
)
)
Second Array:
Array
(
[0] => Array
(
[d] => 4
[e] => 5
[f] => 6
)
[1] => Array
(
[d] => 6
[e] => 5
[f] => 4
)
)
I want this result. Does somebody know how to do this?
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[0] => 3
[1] => 2
[2] => 1
)
[2] => Array
(
[0] => 4
[1] => 5
[2] => 6
)
[3] => Array
(
[0] => 6
[1] => 5
[2] => 4
)
)
Hope you have understand the question.
Thank you in advance.
Try array_merge:
$result = array_merge($array1, $array2);
FIXED (again)
function array_merge_to_indexed () {
$result = array();
foreach (func_get_args() as $arg) {
foreach ($arg as $innerArr) {
$result[] = array_values($innerArr);
}
}
return $result;
}
Accepts an unlimited number of input arrays, merges all sub arrays into one container as indexed arrays, and returns the result.
EDIT 03/2014: Improved readability and efficiency
more simple and modern way is:
$merged = $array1 + ['apple' => 10, 'orange' => 20] + ['cherry' => 12, 'grape' => 32];
new array syntax from php 5.4
If you want to return the exact result you specify in your question then something like this will work
function array_merge_no_keys() {
$result = array();
$arrays = func_get_args();
foreach( $arrays as $array ) {
if( is_array( $array ) ) {
foreach( $array as $subArray ) {
$result[] = array_values( $subArray );
}
}
}
return $result;
}
As a purely native function solution, merge the arrays, then reindex each subarray.
Code: (Demo)
$a = [
['a' => 1, 'b' => 2, 'c' => 3],
['a' => 3, 'b' => 2, 'c' => 1],
];
$b = [
['d' => 4, 'e' => 5, 'f' => 6],
['d' => 6, 'e' => 5, 'f' => 4],
];
var_export(
array_map('array_values' array_merge($a, $b))
);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
2 => 3,
),
1 =>
array (
0 => 3,
1 => 2,
2 => 1,
),
2 =>
array (
0 => 4,
1 => 5,
2 => 6,
),
3 =>
array (
0 => 6,
1 => 5,
2 => 4,
),
)

Categories