PHP remove array in array by using another array - php

I have 2 arrays. The first is my array and the second is the API response :
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
I'd like to remove in array1 all id in array2 who have a status false, or keep all id with status true
In this example I need to get :
$array1 = [
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 12, "name" => "tototo"]
];
Because id 45 and 82 are false in the second array, then I remove them from the first array.
How I can do that without using multiple loops ? There is a solution if we play with php functions like array_diff or something like this ?

You can use array_filter to filter the $array1. Return true if id exist and status is true.
$array1 = ...
$array2 = ...
$result = array_filter($array1, function( $o ) use( $array2 ) {
return isset( $array2[ $o["id"] ] ) && $array2[ $o["id"] ]["status"];
});
This will result to:
Array
(
[1] => Array
(
[id] => 50
[name] => tata
)
[2] => Array
(
[id] => 31
[name] => titi
)
[4] => Array
(
[id] => 12
[name] => tototo
)
)

The most readable solution is often better than using fancy array_* functions, i.e. in this case a simple foreach loop is sufficient:
https://3v4l.org/5eNEf
<?php
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
$result = [];
foreach($array1 as $arrayEl) {
$id = $arrayEl['id'];
if($array2[$id]['status'] === true) {
$result[] = $arrayEl;
}
}
var_dump($result);
Note: We are not modifying the original content but create a new result array. You might want to add additional isset checks depending on what keys your array contains/might not contain.

Please try this code.
<?php
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
foreach($array1 AS $key => $value){
if(!$array2[$value['id']]['status']){
unset($array1[$key]);
}
}
echo "<pre>";
print_r($array1);
?>
Find the key from first array and unset it using the true or false value.
Output:
Array
(
[1] => Array
(
[id] => 50
[name] => tata
)
[2] => Array
(
[id] => 31
[name] => titi
)
[4] => Array
(
[id] => 12
[name] => tototo
)
)

You can use array_walk
$res=[];
array_walk($array1, function(&$v,$k) use (&$res,$array2){
($array2[$v['id']]['status'] == 1) ? ($res[] = $v): '';
});
Live Demo

Here is one more solution for the same,
array_walk($array1, function(&$item,$key) use(&$array1, $array2){
if(!$array2[$item['id']]['status']) // checking status if false
unset($array1[array_search($item['id'], array_column($array1,'id'))]); // then unset
});
print_r($array1);
array_walk — Apply a user supplied function to every member of an array
array_search — Searches the array for a given value and returns the first corresponding key if successful
array_column — Return the values from a single column in the input array
Working demo.

This is probably the least readable solution :-)
Array_intersect and array_column can also get the job done.
I make both arrays associative on id then use array_intersect_key to get the true values.
// Make $array1 associative.
$array1 = array_column($array1, null, "id");
// Find all true values in $array1 from $array2
$result = array_intersect_key($array1, array_intersect(array_combine(array_keys($array2), array_column($array2, "status")), [true]));
https://3v4l.org/QVoI5

$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
foreach ($array1 as $tocheck) {
if ($array2[$tocheck['id']]['status']) {
$new[] = $tocheck;
}
}
print_r($new);

Related

Where two id matching, erase the value in two arrays

I have two arrays like this :
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
I would like to put the value in $data in the value of $data2 instead of "null" values where the ID are matching.
How can I do this ?
I try to do this but does not work :
foreach ($data2['custom'] as $d) {
foreach ($data as $cf) {
if ($cf['id'] == $d['id']):
$cf['value'] = $d['value'];
endif;
}
}
Thanks
Here is a suggestion, first transform the $data array into an array with the id as a key to make the following process simple.
Then process over the $data2 array and in the foreach us the & reference indicator, so that amendments inside the foreach loop are applied to the original $data2 array and not the copy of the $data2 array that would normally be created as part of a foreach loop
$data = [ ['id' => 123, 'value' => 'Text'],['id' => 124, 'value' => 12] ];
$data2 = [ "custom" => [
['id' => 123, 'name' => 'Custom1', 'value' => null],
['id' => 124, 'name' => 'Custom2', 'value' => null]]
];
// transform $data into an array with a useful key
foreach( $data as $d){
$useful[$d['id']] = $d['value'];
}
foreach ( $data2['custom'] as &$data ) {
// first check that the id exists in the new useful array
if ( isset($useful[$data['id']]) ) {
// if it does apply the value to the data2 array
$data['value'] = $useful[$data['id']];
}
}
print_r($data2);
RESULT
Array
(
[custom] => Array
(
[0] => Array
(
[id] => 123
[name] => Custom1
[value] => Text
)
[1] => Array
(
[id] => 124
[name] => Custom2
[value] => 12
)
)
)
In reply to your comment about doing it without using the reference in the loop, yes like this
foreach ( $data2['custom'] as $idx => $data ) {
if ( isset($useful[$data['id']]) ) {
$data2['custom'][$idx]['value'] = $useful[$data['id']];
}
}
Check out this one:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data2['custom'] as $d) {
foreach ($data as $key => $cf) {
if ($cf['id'] == $d['id']):
$data2['custom'][$key]['value'] = $cf['value'];
endif;
}
}
print_r($data2);
You could try to iterate the first array and put the values of it inside the second. If they're always the same size.
Using a foreach go trough the elements on the first array and get the values:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12
]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data as $key=>$singleData){
$data2['custom'][$key]['value'] = $singleData['value'];
}
var_dump($data2);
The ouptup from var_dump() will be:
array(1) {
["custom"]=>
array(2) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(7) "Custom1"
["value"]=>
string(4) "Text"
}
[1]=>
array(3) {
["id"]=>
int(124)
["name"]=>
string(7) "Custom2"
["value"]=>
int(12)
}
}
}

Merging the two array of arrays based on a field value

There are two arrays of arrays. $user and $experience are two arrays and i want to achieve $final as my expected output.
I have two arrays:
$user = [
[
"country" => "aus",
"new_experiences" => 0,
"new_users" => 6
],
[
"country" => "jpn",
"new_experiences" => 0,
"new_users" => 5
]
];
$experience = [
[
"country" => "jpn",
"new_experiences" => 12,
"new_users" => 0
],
[
"country" => "usa",
"new_experiences" => 10,
"new_users" => 0
]
];
After merging these two arrays based on country, how can i get:
$final = [
[
"country" => "aus",
"new_experiences" => 0,
"new_users" => 6
],
[
"country" => "jpn",
"new_experiences" => 12,
"new_users" => 5
],
[
"country" => "usa",
"new_experiences" => 10,
"new_users" => 0
]
];
Try this
array_unique(array_merge($array1,$array2), SORT_REGULAR);
http://se2.php.net/manual/en/function.array-unique.php
You can achieve your GOal using this simple steps:
Iterate and arrange your array into a single array using foreach
Create a key-value array, just like I have created $issetArray
Push all the value in a $final array, you will get the desired output
I have created a simple logic using foreach loop, isset() and array_push()
$user = array(
array(
"country" => "aus",
"new_experiences" => 0,
"new_users" => 6
),
array(
"country" => "jpn",
"new_experiences" => 0,
"new_users" => 5
)
);
$experience = array(
array(
"country" => "jpn",
"new_experiences" => 12,
"new_users" => 0
),
array(
"country" => "usa",
"new_experiences" => 10,
"new_users" => 0
)
);
$final = array();
$issetArray = array();
foreach($user as $key => $value)
{
if(isset($issetArray[$value['country']]))
{
$issetArray[$value['country']]['new_experiences'] = $value;
$issetArray[$value['country']]['new_users'] = $value;
}
else
{
$issetArray[$value['country']] = $value;
}
}
foreach($experience as $key => $value)
{
if(isset($issetArray[$value['country']]))
{
$issetArray[$value['country']]['new_experiences'] = $value['new_experiences'];
$issetArray[$value['country']]['new_users'] = $value['new_users'];
}
else
{
$issetArray[$value['country']] = $value;
}
}
foreach($issetArray as $value)
{
array_push($final, $value);
}
echo "<pre>";
print_r($final);
Click on the link to know more about isset() and array_push()

Find a two-dimensional array to find the sum of multiple elements without loop?

my array:
$data = [
0 => [
"id" => "23",
"to_user_id" => "6",
"from_user_id" => "1",
"month" => "201810",
"add_time" => "1540795976",
"f1" => 10,"f2" => 0,"f3" => 0,"f4" => 0, "f5" => 0,"f6" => 55,"f7" => 0,"f8" => 0,"f9" => 77,"f10" => 0,"f11" => 0,"f12" => 99,"f13" => 77,"f14" => 66,"f15" => 55,
"score" => 0
],
1 => [
"id" => "24",
"to_user_id" => "6",
"from_user_id" => "1",
"month" => "201810",
"add_time" => "1540795976",
"f1" => 10,"f2" => 0,"f3" => 0,"f4" => 0, "f5" => 0,"f6" => 55,"f7" => 0,"f8" => 0,"f9" => 77,"f10" => 0,"f11" => 0,"f12" => 99,"f13" => 77,"f14" => 66,"f15" => 55,
"score" => 0
]
];
I need to get the sum of f1-f15. here is my code:
echo array_sum(array_map(function ($val){
return $val['f1']+$val['f2']+$val['f3']+$val['f4']+$val['f5']+$val['f6']+$val['f7']+$val['f8']+$val['f9']+$val['f10']+$val['f11']+$val['f12']+$val['f13']+$val['f14']+$val['f15'];
},$data));
It doesn't look too good, is there a better way to implement it? thanks!
You can use array_filter with regex to select only needed keys
$res = [];
foreach($data as $item) {
$res[] = array_sum(array_filter($item, function ($x) { return preg_match('/^f\d+$/', $x); }, ARRAY_FILTER_USE_KEY ));
}
print_r($res);
demo
A slight variation on what you are already doing, but changing the way that the items are extracted. This uses another array of the keys your after and then uses array_intersect_key() to filter out all of the other values and then uses array_sum() instead of the adding each item together...
$extract = ["f1" => 0, "f2" => 0, "f3" => 0, "f4" => 0, "f5" => 0,
"f6" => 0, "f7" => 0, "f8" => 0, "f9" => 0, "f10" => 0, "f11" => 0,
"f12" => 0, "f13" => 0, "f14" => 0, "f15" => 0 ];
echo array_sum(array_map(function ($val) use ($extract) {
return array_sum(array_intersect_key($val, $extract));
}, $data));

Merge two pairs in the same array if the pairs have the same value

I have the following pairs and they are in the same array:
[
["ID" => 0, "User" => "Test" , "Type" => 3, "Target" => "Caris"],
["ID" => 1, "User" => "Test1", "Type" => 3, "Target" => "Caris"],
["ID" => 2, "User" => "Test2", "Type" => 4, "Target" => "Shirone"],
["ID" => 3, "User" => "Test3", "Type" => 3, "Target" => "Caris"]
]
I want to get the kinds of them, so I using the following code:
$SortList = [];
foreach($Notif as $Key => $Value)
array_push($SortList, ['Type' => $Value['Type'],
'Target' => $Value['Target']]);
and get this:
[
["Type" => 3, "Target" => "Caris"],
["Type" => 3, "Target" => "Caris"],
["Type" => 4, "Target" => "Shirone"],
["Type" => 3, "Target" => "Caris"]
]
But what I really want is something like this:
[
["Type" => 3, "Target" => "Caris"],
["Type" => 4, "Target" => "Shirone"]
]
I want to merge the pairs if they were same value,
(array_merge() seems can only used for non-pair)
How can I merge them like something above?
$SortList = [];
foreach($Notif as $Key => $Value) {
// Just save only value for the same pair, use them concatenated as the key
$SortList[$Value['Type']."_".$Value['Target']] =
array('Type' => $Value['Type'], 'Target' => $Value['Target']);
}
// remove extra stuff (the keys) that was added to prevent duplicates
$SortList = array_values($SortList);

Populate multidimensional array's rank column with dense rank number

My array structure is as follows -
[
[
"points" => 10,
"details" => ["name" => "Team A", "rank" => ""]
],
[
"points" => 10,
"details" => ["name" => "Team B", "rank" => ""]
],
[
"points" => 8,
"details" => ["name" => "Team C", "rank" => ""]
],
[
"points" => 6,
"details" => ["name" => "Team D", "rank" => ""]
],
]
Now I want populate the array's "rank" value with the appropriate dense rank. Expected result:
[
[
"points" => 10,
"details" => ["name" => "Team A", "rank" => 1]
],
[
"points" => 10,
"details" => ["name" => "Team B", "rank" => 1]
],
[
"points" => 8,
"details" => ["name" => "Team C", "rank" => 2]
],
[
"points" => 6,
"details" => ["name" => "Team D", "rank" => 3]
],
]
How can I achieve this output? I tried looping through each element in the array and comparing points, but I didn't find that to be really efficient.
How about to create another array and store desired result there
$array = array(
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
)
);
$c = 0; // count identifier
$n = array(); // create new array
for ($i=0;$i<count($array);$i++){ // loop through each array
foreach ($array[$i] as $value){ // loop through into sub arrays
if (is_array($value)){
$n[$i]['details'] = array(
"name" => $value['name'],
"rank" => $c
);
$c++;
} else {
$n[$i]['points'] = $value;
}
}
}
print_r($n);
Output will be:
Array ( [0] => Array ( [points] => 10 [details] => Array ( [name] => Team A [rank] => 0 ) ) [1] => Array ( [points] => 11 [details] => Array ( [name] => Team B [rank] => 1 ) ) )
A bit bruteforce but it should work.
$array = array(
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
),
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
)
);
$points = array();
foreach($array as $key => $arr){
$points[] = $arr['points'];
}
asort($points);
foreach($points as $pkey => $point){
foreach($array as $akey => $arr){
if($point == $arr['points']){
$array[$akey]['details']['rank'] = $pkey+1;
}
}
}
var_dump($array);
Since your multidimensional input array is already sorted descending by the points column, you can loop through the array and modify its rank data by reference while conditionally incrementing the rank variable.
Code: (Demo)
$denseRank = 0;
foreach ($array as ['points'=> $points, 'details' => ['rank' => &$rank]]) {
$denseRanks[$points] ??= ++$denseRank;
$rank = $denseRanks[$points];
}
var_export($array);
The above snippet uses "array destructuring" in the foreach() to declare only used variables; it is just as viable to declare &$row and then access its elements in the loop's body.

Categories