PHP Array Filter Multi Level
$users = array();
$users[0]['id'] = 7;
$users[0]['username'] = 'coin';
$users[0]['rooms'][0]['socket'] = 'XXXX';
$users[0]['rooms'][0]['room'] = 1;
$users[1]['id'] = 8;
$users[1]['username'] = 'asdasd';
$users[1]['rooms'][0]['socket'] = 'AAAA';
$users[1]['rooms'][0]['room'] = 2;
I want to get the room value of the member whose socket value is AAAA
.
With Array filter I can do it when there is only one depth, but I am stuck at multiple depths.
I'd appreciate it if you could offer something other than foreach. Thanks.
The following attempt is unsuccessful.
$socket = 'AAAA';
$room_detect = array_filter($users, function($v, $k) use ($socket) {
if(array_search($socket, $v['rooms']))
{
return $v;
}
}, ARRAY_FILTER_USE_BOTH);
Answer
Solution:
You can adopt a recursive approach to make it work for any depth.
- Loop over the current level of the array.
- If the key in the current loop at hand is a
socket
and it matches the value you are searching for, access theroom
key instantly and return the value. - If you can't find the socket at all, return
false
.
Snippet:
<?php
function findSocket($data,$socket_value){
foreach($data as $key => $value){
if(is_array($value)){
$res = findSocket($value,$socket_value);
if($res !== false) return $res;
}else if($key == 'socket' && $value === $socket_value){
return $data['room']; // because socket and room keys are on the same level
}
}
return false;
}
$room_no = findSocket($users,'AAAA');
if($room_no == false){
die("Room not found");
}
echo $room_no;
Answer
Solution:
Option 1: array_filter - you were very close in your attempt. I added array_merge to flatten the array_column and simplified your logic a bit
<?php
$users = array();
$users[0]['id'] = 7;
$users[0]['username'] = 'coin';
$users[0]['rooms'][0]['socket'] = 'XXXX';
$users[0]['rooms'][0]['room'] = 1;
$users[1]['id'] = 8;
$users[1]['username'] = 'asdasd';
$users[1]['rooms'][0]['socket'] = 'AAAA';
$users[1]['rooms'][0]['room'] = 2;
$users[1]['rooms'][1]['socket'] = 'BBBB';
$users[1]['rooms'][1]['room'] = 4;
$socket = 'AAAA';
$room_detect = array_filter(array_merge(...array_column($users,'rooms')), function($v, $k) use ($socket)
{ return $v['socket']===$socket;} , ARRAY_FILTER_USE_BOTH);
print_r($room_detect);
Example: https://www.tehplayground.com/KVK1Ur0KTJYn0H3L
Option 2: a hack - but if you have a zillion users in that array, this might be the fastest. I'll probably get into trouble but:
<?php
// example code
$users = array();
$users[0]['id'] = 7;
$users[0]['username'] = 'coin';
$users[0]['rooms'][0]['socket'] = 'XXXX';
$users[0]['rooms'][0]['room'] = 1;
$users[1]['id'] = 8;
$users[1]['username'] = 'asdasd';
$users[1]['rooms'][0]['socket'] = 'AAAA';
$users[1]['rooms'][0]['room'] = 2;
function getRoomOf($user, $u) {
return preg_replace('/\D/', '', explode('"room":',explode('"'.$user.'"', $u)[1])[1]);
}
print_r(getRoomOf('AAAA', json_encode($users)));
Example at: https://www.tehplayground.com/zpsDkRkPCEAXmQpY
Answer
Solution:
$users = array();
$users[0]['id'] = 7;
$users[0]['username'] = 'coin';
$users[0]['rooms'][0]['socket'] = 'XXXX';
$users[0]['rooms'][0]['room'] = 1;
$users[1]['id'] = 8;
$users[1]['username'] = 'asdasd';
$users[1]['rooms'][0]['socket'] = 'AAAA';
$users[1]['rooms'][0]['room'] = 2;
$users[1]['rooms'][1]['socket'] = 'BBBB';
$users[1]['rooms'][1]['room'] = 4;
$socket = 'AAAA';
$room_detect = array_filter(array_column($users,'rooms'), function($v, $k) use ($socket)
{
foreach($v as $room)
{
if($room['socket']===$socket)
{
return true;
}
}
}, ARRAY_FILTER_USE_BOTH);
print_r($room_detect);
RESULT
(
[1] => Array
(
[0] => Array
(
[socket] => AAAA
[room] => 2
)
[1] => Array
(
[socket] => BBBB
[room] => 4
)
)
)
I want it as below.
[0] => Array
(
[socket] => AAAA
[room] => 2
)
Source