Find duplicate array values and delete conditionally - php

I have an multidimensional array like this:
$orders = array(
array(
'id' => '123',
'name' => 'John',
'lastname'=>'Carter',
'rate' => '1.0'
),
array(
'id' => '546',
'name' => 'Ben',
'lastname'=>'Wall',
'rate' => '0.25'
),
array(
'id' => '666',
'name' => 'John Bow',
'lastname'=>'Porter',
'rate' => '0.25'
),
array(
'id' => '156',
'name' => 'John',
'lastname'=>'Carter',
'rate' => '0.5'
)
);
and want make a function that will be delete duplicate rows that rate < 1.0. The result array should be:
$orders = array(
array(
'id' => '123',
'name' => 'John',
'lastname'=>'Carter',
'rate' => '1.0'
),
array(
'id' => '546',
'name' => 'Ben',
'lastname'=>'Wall',
'rate' => '0.25'
),
array(
'id' => '666',
'name' => 'John',
'lastname'=>'Porter',
'rate' => '0.25'
)
);

Not very beautiful and speed, but workable solution:
$a = array(...); // Your array
$hashstack = array_map(function($value) { return md5($value['name'] . $value['lastname']); }, $a);
$result = array_filter($a, function($value) use ($hashstack)
{
if ((float)$value['rate'] < 1.0) {
$count = 0;
foreach ($hashstack as $hash) {
if (md5($value['name'] . $value['lastname']) == $hash) {
$count++;
}
}
if ($count > 1) {
unset($value);
return;
}
}
return $value;
});
Result is the same of yours.

Edit: Second and good version here: http://ideone.com/zJ8vj
What do You mean by 'duplicated' - same 'rate' ?
Bellow example remove duplicated orders with same 'rate' and 'rate' < 1.0.
Is this what You need ?
$tmpOrders = array();
foreach($orders as $order) {
// Check only rate < 1.0
if((float)$order['rate'] < 1.0) {
// Check duplicate
$exists = false;
foreach($tmpOrders as $tmp) {
if($tmp['rate'] == $order['rate']) {
$exists = true;
break;
}
}
// Add if rate not exists
if(!$exists) {
$tmpOrders[] = $order;
}
}
// Add all with rate >= 1.0
else {
$tmpOrders[] = $order;
}
}
$orders = $tmpOrders;
echo "<pre>";
print_r($orders);
echo "<pre>";
Result:
Array
(
[0] => Array
(
[id] => 123
[name] => John
[lastname] => Carter
[rate] => 1.0
)
[1] => Array
(
[id] => 546
[name] => Ben
[lastname] => Wall
[rate] => 0.25
)
[2] => Array
(
[id] => 156
[name] => John
[lastname] => Carter
[rate] => 0.5
)
)

Related

Compare and combine multidimensional array then sort descending PHP

I have 2 multi arrays, profiles and encoded arrays like this
$profiles = array(
array(
'user_id' => 'fcc3d884-fbef-438a-9c86-0ad52c9b1223',
'first_name' => 'Narñia',
'middle_name' => 'Ñ',
'last_name' => 'Cruz',
'ext' => ''
),
array(
'user_id' => '0d31557d-1e9f-4db3-ac0d-72e1709fe89c',
'first_name' => 'Randy',
'middle_name' => 'O',
'last_name' => 'Rocker',
'ext' => ''
),
array(
'user_id' => '0f93f169-cf56-49df-a76b-7596446104c6',
'first_name' => 'Qwerty',
'middle_name' => 'K',
'last_name' => 'Asdfg',
'ext' => ''
),
array(
'user_id' => '23b1f4a2-034c-43b4-96b7-3191d78cead1',
'first_name' => 'Johny',
'middle_name' => 'L',
'last_name' => 'Walker',
'ext' => ''
)
);
$encoded = array(
array(
'encoder_id' => '0d31557d-1e9f-4db3-ac0d-72e1709fe89c',
'fullname' => 'Randy O. Rocker',
'encoded' => 10,
),
array(
'encoder_id' => '23b1f4a2-034c-43b4-96b7-3191d78cead1',
'fullname' => 'John L. Walker',
'encoded' => 20,
)
);
Now i want to get some data from $profiles then combine to $encoded array when user_id and encoder_id is match, i have this code but it seems wrong it only gets "John L. Waler" data. here's my code.
$data = [];
foreach ($profiles as $key => $val) {
$user_id = $val['user_id'];
foreach($encoded as $k => $v){
$ext_name = ($val['ext'] == '') ? '' : $val['ext'];
$fullname = $val['first_name'].' '.substr($val['middle_name'], 0, 1).'. '.$val['last_name'].' '.$ext_name;
$data[$key] = array(
'id' => ($v['encoder_id'] == $user_id) ? $v['encoder_id'] : $user_id,
'fullname' => ($v['encoder_id'] == $user_id) ? $v['fullname'] : $fullname,
'encoded' => ($v['encoder_id'] == $user_id) ? $v['encoded'] : 0
);
}
}
echo '<pre>';
print_r($data);
echo '</pre>';
here's the result
Array
(
[0] => Array
(
[id] => fcc3d884-fbef-438a-9c86-0ad52c9b1223
[fullname] => Narñia �. Cruz
[encoded] => 0
)
[1] => Array
(
[id] => 0d31557d-1e9f-4db3-ac0d-72e1709fe89c
[fullname] => Randy O. Rocker
[encoded] => 0 //this should be 10
)
[2] => Array
(
[id] => 0f93f169-cf56-49df-a76b-7596446104c6
[fullname] => Qwerty K. Asdfg
[encoded] => 0
)
[3] => Array
(
[id] => 23b1f4a2-034c-43b4-96b7-3191d78cead1
[fullname] => John L. Walker
[encoded] => 20
)
)
Also after combining them to a new array. i want to sort the new array by "encoded" attribute descending.
Thank you for understanding
You can make your life easier by re-indexing the $encoded array by the encoder_id values using array_column; then you don't have to search the array each time to look for a user_id value, you can just use isset. Once you've extracted your data, you can use usort to sort by the encoded values:
$encoded_ids = array_column($encoded, null, 'encoder_id');
$data = array();
foreach ($profiles as $profile) {
$user_id = $profile['user_id'];
if (isset($encoded_ids[$user_id])) {
$data[] = array('id' => $user_id,
'fullname' => $encoded_ids[$user_id]['fullname'],
'encoded' => $encoded_ids[$user_id]['encoded']
);
}
else {
$data[] = array('id' => $user_id,
'fullname' => "${profile['first_name']} ${profile['middle_name']} ${profile['last_name']}",
'encoded' => 0
);
}
}
usort($data, function ($a, $b) { return $b['encoded'] - $a['encoded'];});
print_r($data);
Output:
Array
(
[0] => Array
(
[id] => 23b1f4a2-034c-43b4-96b7-3191d78cead1
[fullname] => John L. Walker
[encoded] => 20
)
[1] => Array
(
[id] => 0d31557d-1e9f-4db3-ac0d-72e1709fe89c
[fullname] => Randy O. Rocker
[encoded] => 10
)
[2] => Array
(
[id] => fcc3d884-fbef-438a-9c86-0ad52c9b1223
[fullname] => Narñia Ñ Cruz
[encoded] => 0
)
[3] => Array
(
[id] => 0f93f169-cf56-49df-a76b-7596446104c6
[fullname] => Qwerty K Asdfg
[encoded] => 0
)
)
Demo on 3v4l.org
An alternative to Nick's version, using array_reduce:
$encodedByEncoderId = array_column($encoded, null, 'encoder_id');
$combined = array_reduce($profiles, function (array $combined, array $profile) use ($encodedByEncoderId): array {
$combined[] = [
'id' => $profile['user_id'],
'fullname' => $encodedByEncoderId[$profile['user_id']]['fullname']
?? "{$profile['first_name']} {$profile['middle_name']}. {$profile['last_name']}",
'encoded' => $encodedByEncoderId[$profile['user_id']]['encoded']
?? 0
];
return $combined;
}, []);
Demo: https://3v4l.org/kKBru
Try this!
$data = [];
foreach ($profiles as $key => $val) {
$user_id = $val['user_id'];
$is_matched = 0;
$encoded_data = [];
foreach($encoded as $k => $v){
if ($user_id == $v['encoder_id']) {
$is_matched = 1;
$encoded_data = $v;
}
}
$ext_name = ($val['ext'] == '') ? '' : $val['ext'];
$fullname = $val['first_name'].' '.substr($val['middle_name'], 0, 1).'. '.$val['last_name'].' '.$ext_name;
$data[$key] = array(
'id' => ($is_matched == 1) ? $encoded_data['encoder_id'] : $user_id,
'fullname' => ($is_matched == 1) ? $encoded_data['fullname'] : $fullname,
'encoded' => ($is_matched == 1) ? $encoded_data['encoded'] : 0
);
}

Count number of values in an array where not 0

I have an array and I'm trying to count the number of objects in the array where the the object key 'Value' is not 0.
array (
0 =>
array (
'name' => 'item[110189]',
'value' => '0',
'primary_key' => '110189',
),
1 =>
array (
'name' => 'item[110190]',
'value' => '50',
'primary_key' => '110190',
),
2 =>
array (
'name' => 'item[110191]',
'value' => '0',
'primary_key' => '110191',
),
3 =>
array (
'name' => 'item[110192]',
'value' => '0',
'primary_key' => '110192',
),
)
I've tried the following:
$input_items = array_filter($request->items, function($item){
$count = 0;
foreach($item as $i){
if(! $i['value'] == 0){
$count = $count + 1;
}
}
return $count;
}); // it will return an array
return $input_items;
I get an error saying invalid object 'Value' which to be honest I half expected.
Changed it this way:
$input_items = array_filter($arr, function ($item) {
return ($item['value'] != 0);
});
Full Code
<?php
$arr = array (
0 =>
array (
'name' => 'item[110189]',
'value' => '0',
'primary_key' => '110189',
),
1 =>
array (
'name' => 'item[110190]',
'value' => '50',
'primary_key' => '110190',
),
2 =>
array (
'name' => 'item[110191]',
'value' => '0',
'primary_key' => '110191',
),
3 =>
array (
'name' => 'item[110192]',
'value' => '0',
'primary_key' => '110192',
),
);
$input_items = array_filter($arr, function ($item) {
return ($item['value'] != 0);
});
print_r($input_items);
Output has only the non-zero entries:
Array
(
[1] => Array
(
[name] => item[110190]
[value] => 50
[primary_key] => 110190
)
)
Demo: http://ideone.com/LUbMSb
You can use array_reduce:
print array_reduce($request->items, function($carry ,$item){
if($item['value'] != 0){
$carry++;
}
return $carry;
},0);

remove duplicate values from multidimensional array by single value

Ok the thing is, Ive read and tried a lot of solutions found here based on complete duplicateness, BUT I need something a little bit different and cant figure it out...
Because I only want to get and remove the duplicate value if only 1 of the array values is duplicate.
And also later combine the two but that's not that difficult.
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
What I want the outcome to be:
$b = array(
array(
'id' => 1,
'qty' => 3
),
array(
'id' => 0,
'qty' => 1
)
);
You can do something like the following:
<?php
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
$idsList = array();
$res = array();
foreach ($a as $arr){
if (!in_array($arr['id'], $idsList)){
$res[$arr['id']] = $arr;
$idsList[] = $arr['id'];
}
else{
$res[$arr['id']]['qty'] += $arr['qty'];
}
}
echo "<pre>";
print_r($res);
To get array like that:
Array
(
[1] => Array
(
[id] => 1
[qty] => 3
)
[0] => Array
(
[id] => 0
[qty] => 1
)
)
Checkout This DEMO: http://codepad.org/UP0G7WnE
$a = array(
array(
'id' => 1,
'qty' => 1
),
array(
'id' => 0,
'qty' => 1
),
array(
'id' => 1,
'qty' => 2
)
);
$b = array();
$ids = array();
for($i = 0; $i < count($a); $i++)
{
if(in_array($a[$i]['id'], $ids))
{
$j = array_search($a[$i]['id'], array_values($ids));
$b[$j]['qty'] += $a[$i]['qty'];
}
else
{
$b[$i]['id'] = $a[$i]['id'];
$b[$i]['qty'] = $a[$i]['qty'];
$ids[] = $a[$i]['id'];
}
}
echo "<pre>";
print_r($b);
This could be a solution:
$temp = array();
foreach ($a as $data){
if (isset($temp[$data['id']])){
$temp[$data['id']] += $data['qty'];
} else {
$temp[$data['id']] = $data['qty'];
}
}
// Format array
$b = array();
foreach ($temp as $id => $qty){
$b[] = array(
'id' => $id,
'qty' => $qty
);
}
Output will be:
Array
(
[0] => Array
(
[id] => 1
[qty] => 3
)
[1] => Array
(
[id] => 0
[qty] => 1
)
)

delete subarrays from multiple array by equal values of key PHP

i faced with problem and i hope that you can help
I have array like this (but with hundreds of subarrays):
Array
(
[0] => Array
(
[id] => 211
[name] => Name
[description] => Desc
[Link] => http://link/211
[previewUrl] => https://link/id885364?mt=8
[payout] => 0.30
[image] => http://link/ios.png
[categories] => Array
(
[0] => iOS
[1] => Games
)
)
[1] => Array
(
[id] => 2
[name] => Name
[description] => Desc
[Link] => http://link/211
[previewUrl] => https://link/id885364?mt=8
[payout] => 2
[image] => http://link/ios.png
[categories] => Array
(
[0] => iOS
[1] => Games
)
)
)
I need to find all subarrays that equals by 'previewUrl' and then find among them one with max value of 'payout' and delete others with smaller value.
Thank you!
Loop through the original array ($arr) collecting the maximum payout values in a temporary array ($max_arr). When a higher payout is found replace the previous higher payout in the temporary array and delete it in the original array. When a lower or equal payout is found delete it.
<?php
$arr = array(array('id' => 211, 'name' => 'Name', 'description' => 'Desc', 'Link' => 'http://link/211', 'previewUrl' => 'https://link/id885364?mt=8', 'payout' => '0.30', 'image' => 'http://link/ios.png', 'categories' => array('0' => 'iOS', '1' => 'Games')), array('id' => 2, 'name' => 'Name', 'description' => 'Desc', 'Link' => 'http://link/211', 'previewUrl' => 'https://link/id885364?mt=8', 'payout' => '2', 'image' => 'http://link/ios.png', 'categories' => array('0' => 'iOS', '1' => 'Games')), array('id' => 11, 'name' => 'Name', 'description' => 'Desc', 'Link' => 'http://link/211', 'previewUrl' => 'https://link/id885364?mt=7', 'payout' => '3', 'image' => 'http://link/ios.png', 'categories' => array('0' => 'iOS', '1' => 'Games')), array('id' => 1, 'name' => 'Name', 'description' => 'Desc', 'Link' => 'http://link/211', 'previewUrl' => 'https://link/id885364?mt=7', 'payout' => '1', 'image' => 'http://link/ios.png', 'categories' => array('0' => 'iOS', '1' => 'Games')));
$max_arr = array(); // temporary array
foreach ( $arr as $key => $value ) {
if ( !isset($max_arr[$value['previewUrl']]) ) {
$max_arr[$value['previewUrl']] = array_merge(array('key' => $key), $value);
}
else {
// higher payout
if ( $max_arr[$value['previewUrl']]['payout'] < $value['payout'] ) {
unset($arr[$max_arr[$value['previewUrl']]['key']]);
$max_arr[$value['previewUrl']] = array_merge(array('key' => $key), $value);
}
else { unset($arr[$key]); } // lower or equal payout
}
}
?>
You can try with the following:
class MyArrayParser{
var $preview_url;
var $max_payout;
function filter_preview_url($subarray)
{
return $subarray["previewUrl"] == $this->preview_url;
}
function filter_payout($subarray)
{
return $subarray["payout"] == $this->max_payout;
}
function search_max_payout_by_previewUrl($big_array,$preview_url)
{
$this->preview_url = $preview_url;
$filtered_array = array_filter($big_array,array($this,"filter_preview_url")); //Only subarrays with previewUrl == $preview_url
function payout_extract($subarray)
{
return $subarray["payout"];
}
$payouts_list = array_map("payout_extract",$filtered_array);
if(count($payouts_list)==0) //PreviewUrl not found
return array();
$this->max_payout = max($payouts_list);
$only_max_payout_list = array_filter($filtered_array,array($this,"filter_payout"));
return $only_max_payout_list;
}
}
$obj = new MyArrayParser();
$filtered_array = $obj->search_max_payout_by_previewUrl($my_big_array,"....previewUrl...."));
Not necessarily fast, but it's pretty easy to understand.
$a = array(
array ('id' => 211,'previewUrl' => 'https://link/id885364?mt=8','payout' => 0.30),
array ('id' => 2,'previewUrl' => 'https://link/id885364?mt=8','payout' => 2));
$searchUrl = 'https://link/id885364?mt=8';
$to_delete = array();
$max_payout = -1;
$max_key = "";
// Loop through array, looking at previewUrls that match.
foreach ($a as $key => $subarray) {
if ($subarray['previewUrl'] == $searchUrl) {
// Save all matches to an array for deletion.
array_push($to_delete, $key);
// Find the element with the highest payout.
if ($subarray['payout'] > $max_payout || $max_payout == -1) {
$max_payout = $subarray['payout'];
$max_key = $key;
}
}
}
// Remove the element with the highest payout.
if (($key = array_search($max_key, $to_delete)) !== false) {
unset($to_delete[$key]);
}
//print $max_payout;
//print $max_key;
//print_r($to_delete);
// Finally, delete all the elements flagged for deletion.
foreach ($to_delete as $key) {
unset($a[$key]);
}
print_r($a);

array_filter with assoc array?

I am using array_filter to do something like this:
function endswithy($value) {
return (substr($value, -1) == 'y');
}
$people = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
$withy = array_filter($people, "endswithy");
var_dump($withy);
BUT with the more option in filter for example
$people = array(
"Johnny"=>array("year"=>1989, "job"=>"prof"),
"Timmy"=>array("year"=>1989, "job"=>"std"),
"Bobby"=>array("year"=>1988),
"Sam"=>array("year"=>1983),
"Tammy"=>array("year"=>1985),
"Danny"=>array("year"=>1983),
"Joe"=>array("year"=>1989,"job"=>"prof"));
OR
$people = array(
array("name"=>"Johnny","year"=>1989, "job"=>"prof"),
array("name"=>"Timmy","year"=>1989, "job"=>"std"),
array("name"=>"Bobby""year"=>1988),
array("name"=>"Sam","year"=>1983),
array("name"=>"Tammy","year"=>1985),
array("name"="Danny","year"=>1983),
array("name"="Joe","year"=>1989,"job"=>"prof"));
How Can I got the only this people (endwith y and year=1989 and job=prof) ,Can I use array_filter?
or any build-in function to do this?
$people = array(
"Johnny"=>array("year"=>1989, "job"=>"prof")
);
OR
$people = array(
array("name="Johnny","year"=>1989, "job"=>"prof")
);
PHP 5.6 introduces the optional flag ARRAY_FILTER_USE_KEY that will allow this:
function endswithy($name) {
return (substr($name, -1) == 'y');
}
$people = array(
"Johnny"=>array("year"=>1989, "job"=>"prof"),
"Timmy"=>array("year"=>1989, "job"=>"std"),
"Bobby"=>array("year"=>1988),
"Sam"=>array("year"=>1983),
"Tammy"=>array("year"=>1985),
"Danny"=>array("year"=>1983),
"Joe"=>array("year"=>1989,"job"=>"prof")
);
$peopleEndingInY = array_filter($people, 'endswithy', ARRAY_FILTER_USE_KEY);
// Outputs: 5
var_dump(count($peopleEndingInY));
If you need to maintain and key and the value, another flag ARRAY_FILTER_USE_BOTH will do that as seen in this example:
$ar = array(
'key1' => 'value1',
'key2' => 'value2'
);
//Note that this doens't actually filter anything since it doesn't return a bool.
$output = array_filter($ar, function($value, $key){
echo sprintf("%s => %s\n", $key, $value);
}, ARRAY_FILTER_USE_BOTH);
Either use foreach with your current array's structure:
$people = array(
"Johnny" => array("year" => 1989, "job" => "prof"),
"Timmy" => array("year" => 1989, "job" => "std"),
"Bobby" => array("year" => 1988),
"Sam" => array("year" => 1983),
"Tammy" => array("year" => 1985),
"Danny" => array("year" => 1983),
"Joe" => array("year" => 1989, "job" => "prof"),
);
foreach ( $people as $name => $info ) {
if ( substr($name, -1) !== 'y' || $info['year'] != 1989 ) {
unset($people[$name]);
}
}
print_r($people);
// output:
Array
(
[Johnny] => Array
(
[year] => 1989
[job] => prof
)
[Timmy] => Array
(
[year] => 1989
[job] => std
)
)
Or convert your array so that name is value of inner array:
$people = array(
array('name' => 'Johnny', 'year' => 1989, 'job' => 'prof'),
array('name' => 'Timmy' , 'year' => 1989, 'job' => 'std'),
array('name' => 'Bobby' , 'year' => 1988),
array('name' => 'Sam' , 'year' => 1983),
array('name' => 'Tammy' , 'year' => 1985),
array('name' => 'Danny' , 'year' => 1983),
array('name' => 'Joe' , 'year' => 1989, 'job' => 'prof'),
);
function filter($item) {
return substr($item['name'], -1) === 'y' && $item['year'] == 1989;
}
$filteredPeople = array_filter($people, 'filter');
print_r($filteredPeople);
// output:
Array
(
[0] => Array
(
[name] => Johnny
[year] => 1989
[job] => prof
)
[1] => Array
(
[name] => Timmy
[year] => 1989
[job] => std
)
)

Categories