Find relative value in array using PHP [duplicate] - php

This question already has answers here:
Filter multidimensional array based on partial match of search value
(3 answers)
Closed 8 months ago.
I'm trying to get the data in the array according to the input value, like the example below, if I enter the correct value, it will get the value, but when I enter the incorrect value, it doesn't work.
You can see a small example below.
<?php
echo "<pre>";
$array = [
[
"id" => "33704",
"name" => "Total apple"
],
[
"id" => "33706",
"name" => "Used apple"
],
[
"id" => "33694",
"name" => "banana: Bits received"
],
[
"id" => "33697",
"name" => "banana: Bits sent"
]
];
print_r($array);
function searchItem($array, $key, $value)
{
$results = array();
if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
$results = array_merge($results, searchItem($subarray, $key, $value));
}
}
return $results;
}
$result = searchItem($array, 'name', 'Bits received');
print_r($result);
When I enter the exact value 'banana: Bits received' it can be retrieved, but the value is many and unlimited, I want when I enter 'Bits received' it must also be found.
Hope everyone can help. Thanks!

you can use strstr or strpos or even preg_match to achieve this.
foreach ($array as $sub) {
if (strstr($sub['name'], $value) !== false) {
// founded value
}
}
however, this may be a more complicated task, you may need to include more advanced techs with this, like databases & Fulltext search, or some indexing softwares like elastic search and so on.

There are built-in functions for this: array_filter and str_contains:
$result = array_filter(
$array,
function ($item) {
return str_contains($item['name'], 'Bits received');
}
);
The same solution with an arrow function:
$result = array_filter(
$array,
fn($item) => str_contains($item['name'], 'Bits received')
);
Moving array_filter into a function:
function searchItem($array, $key, $value) {
return array_filter(
$array,
fn($item) => str_contains($item[$key], $value)
);
}
$result = searchItem($array, 'name', 'Bits received');
print_r($result);

Related

Get key (not index) from qualifying row in an associative array of associative arrays

Here my array:
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
With the value 'qwerty' I would like to retrieve the 'key1'.
I looking for something like that:
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
But I get '0', instead of 'key1' (and I know that's how it works)
Anyone know how to adapt this code or know another code to get the key value?
Slight modification to your code to combine the keys and column values:
$theKeyIWant = array_search('qwerty', array_combine(array_keys($array), array_column($array, 'second')));
The problem with seeking "something sexier" for this task is that if "sexier" means a "functional iterator", then that comes a cost of not being able to "return early" (doing unnecessary cycles).
If you want a single-line function to call, you can build your own and put it in a helpers file somewhere in your project. My strong advice is to abandon "sexy" for this task and use a breakable foreach loop.
Code: (Demo)
function getRowKey($array, $column, $value) {
foreach ($array as $key => $row) {
if ($row[$column] === $value) {
return $key;
}
}
return null;
}
var_export(getRowKey($array, 'second', 'qwerty'));
If you are going to perform repeated searches on the same array and the second column is guaranteed to contain unique values, then you can convert the array into a lookup array without losing any data. (Demo)
function restructure($array, $columnToKey) {
$result = [];
foreach ($array as $key => $row) {
$result[$row[$columnToKey]] = $row + ['oldKey' => $key];
}
return $result;
}
var_export(restructure($array, 'second')['qwerty']);
To solve this is to loop through the outer array and use array_search() to search for the value within each inner array.
$value = 'qwerty';
$theKeyIWant = null;
foreach ($array as $key => $innerArray) {
if (array_search($value, $innerArray) !== false) {
$theKeyIWant = $key;
break;
}
}
echo $theKeyIWant; // Output: key1
array_keys returns an array of an array's keys.
<?php
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
echo array_keys($array)[$theKeyIWant];
?>
3V4l

Find elements with empty value in multidimensional array

I have an array like the below:
$arrays = [
'a' => [
'name' => "Name 1",
'age' => "99",
'add' => ""
],
'b' => [
'name' => "Name 2",
'age' => "99",
'add' => "Add2"
],
'c' => [
'name' => "Name 3",
'age' => "99",
'add' => "Add3"
],
'd' => [
'name' => "",
'age' => "",
'add' => "Add4"
]
];
I want to get a result like:
$res = [
'a' => ['add'],
'd' => ['name','age']
];
I have tried with the below code, but it returns 1.
$status = array_walk_recursive($arrays, function($v, $k) {
global $output;
if (empty($v) && $v !== 0)
$output[$k] = $v;
});
I want to do it without using any loops because my real input array is very large and I am concerned with performance.
If your input is always of a fixed depth, you can map the existing values to the keys of all empty items:
$output = array_map(function($row) {
return array_keys(array_filter($row, function ($e) {
return empty($e) && $e !== 0;
}));
}, $arrays);
The outer function runs for each "row", the value of which is then converted into a list of all keys with empty values (excluding zeroes, as in the question).
This will keep the outer keys B & C as empty arrays, so if you want them to be removed as well then run another iteration of array_filter over the result:
$output = array_filter($output)
See https://3v4l.org/c23ZB
As mentioned in the comments, there are still several loops going on here, they're just not as visible in the code. A regular foreach loop might end up being a lot easier to read, and possibly perform faster as well.
You can use next combination of array_walk & array_filter:
$result = [];
array_walk(
$arrays,
function($el, $key) use(&$result) {
$empty = array_filter($el, function($el){return $el == "";});
$empty_keys = array_keys($empty);
if (count($empty_keys)) $result[$key] = $empty_keys;
}
);
Try it here
This is another way to achieve your desired output.
$result = [];
foreach($arrays as $key => $value) {
$empty_arr = array_filter($value, function ($ele) {
return empty($ele);
});
$empty_arr_keys = array_keys($empty_arr);
if(!empty($empty_arr_keys)) $result[$key] = $empty_arr_keys;
}
print_r($result);
#iainn's answer can be sharpened up by calling !strlen() on the deep values.
Code: (Demo)
var_export(
array_filter(
array_map(
fn($row) => array_keys(
array_filter(
$row,
fn($v) => !strlen($v)
)
),
$array
)
)
);
But you will end up making fewer iterations and writing cleaner, more intuitive/readable code if you use classic loops. This is how I would write it in my own project:
Code: (Demo)
$result = [];
foreach ($array as $rowKey => $row) {
foreach ($row as $key => $value) {
if (!strlen($value)) {
$result[$rowKey][] = $key;
}
}
}
var_export($result);

How do I get the value of the first occurrence of array_walk_recursive in php

I have a deep multidimensional array that I am needing to extract the value of a specific key. I have found that the array_walk_recursive function will be my best option. I only need the first occurrence.
My array looks like this - (except much more complicated)
Array (
[vehicle info] => Array (
[one] => Array (
[submodel] => LX
[engine] => 2.3
)
[two] => Array (
[color] => blue
[year] => 2007
[wheels] => 4
)
[three] => Array (
[submodel] => LX
[make] => Ford
[model] => F-150
[offroad] => No
)
)
)
The issue here is, submodel is in both one and three. Additionally, the array is not consistent, so I must use array_walk_recursive to search through it for the matching key, then return the value for that key.
Here is my current code -
array_walk_recursive ($array, (function ($item, $key) {
$wanted = "submodel";
if ($key === $wanted) {
echo ("$key is $item");
}
}));
The above returns submodel is LXsubmodel is LX.
Bonus Question!!
How can I search for multiple keys and return the first corresponding value for each of those? I was thinking putting all wanted keys in an array, then do a foreach loop, but don't quite know how to structure this. I am new to php.
array_walk_recursive() is the appropriate native function to call for this task. Keep track of which keys have already been declared in the result array and ensure that they are never overwritten.
Code: (Demo)
$needles = ['submodel', 'offroad'];
$result = [];
array_walk_recursive(
$array,
function($value, $key) use ($needles, &$result) {
if (
in_array($key, $needles)
&& !isset($result[$key])
) {
$result[$key] = "$key is $value";
}
}
);
var_export($result);
Output:
array (
'submodel' => 'submodel is LX',
'offroad' => 'offroad is No',
)
If your application has performance concerns, then the native function becomes less attractive because it will always iterate the entire input array's structure -- even after all sought keys are encountered. If you want to "break early" (short circuit), then you will need to design your own recursive function which will return when all sought keys are found.
Code: (Demo)
$soughtKeys = array_flip(['submodel', 'offroad']);
function earlyReturningRecursion(array $array, array $soughtKeys, array &$result = []): array
{
foreach ($array as $key => $value) {
if (!array_diff_key($soughtKeys, $result)) { // check if result is complete
return $result;
} elseif (is_array($value)) {
earlyReturningRecursion($value, $soughtKeys, $result);
} elseif (isset($soughtKeys[$key]) && !isset($result[$key])) {
$result[$key] = "$key is $value";
}
}
return $result;
}
var_export(earlyReturningRecursion($array, $soughtKeys));
// same output as the first snippet
I would start by setting the values you want to null, and then only saving them if they haven't been found yet, by checking is_null(). I haven't tested this code, but it should look something like this:
$submodel = null;
array_walk_recursive ($array, (function ($item, $key) {
$wanted = "submodel";
if ($key === $wanted && is_null($submodel)) {
echo ("$key is $item");
$submodel = $item;
}
}));
array_walk_recursive() has the defect of not allowing to return matching results however in PHP 7 you could use an anonymous function and a variable to store the matching value.
$matching = null;
$wanted = "submodel";
array_walk_recursive ($array, function ($item, $key) use ($wanted, $matching) {
if (($key === $wanted) && is_null($matching)) {
$matching = $item;
}
});
As far as there is no way to return early from array_walk_recursive(), I'd suggest to create a function to find the first occurrence of $wanted:
$arr = [
'vehicle info' => [
'one' => ['submodel' => 'LX', 'engine' => '2.3'],
'two' => ['color' => 'blue', 'year' => '2007', 'wheels' => '4'],
'three' => ['submodel' => 'LX', 'make' => 'Ford', 'model' => 'F-150', 'offroad' => 'No'],
],
];
function find($needle, $haystack, $found = '')
{
foreach ($haystack as $key => $value) {
if ($found) {
break;
}
if ($key === $needle) {
$found = "{$needle} is {$value}";
break;
}
if (is_array($value)) {
$found = find($needle, $value, $found);
}
}
return $found;
}
$wanted = 'submodel';
$result = find($wanted, $arr);
var_dump($result); // string(14) "submodel is LX"
Live demo
Update: to search for multiple keys you'll need to do it in a loop:
$multiple_keys = array('submodel', 'year');
foreach ($multiple_keys as $wanted) {
var_dump(find($wanted, $arr));
}
// Output:
// string(14) "submodel is LX"
// string(12) "year is 2007"
Live demo

How to check if a specific value exists at a specific key in any subarray of a multidimensional array?

I need to search a multidimensional array for a specific value in any of the indexed subarrays.
In other words, I need to check a single column of the multidimensional array for a value. If the value exists anywhere in the multidimensional array, I would like to return true otherwise false
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
I would like to know the fastest and most efficient way to check if the array $my_array contains a value with the key "id". For example, if id => 152 anywhere in the multidimensional array, I would like true.
Nothing will be faster than a simple loop. You can mix-and-match some array functions to do it, but they'll just be implemented as a loop too.
function whatever($array, $key, $val) {
foreach ($array as $item)
if (isset($item[$key]) && $item[$key] == $val)
return true;
return false;
}
The simplest way is this:
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
if (array_search(152, array_column($my_array, 'id')) !== FALSE) {
echo 'FOUND!';
} else {
echo 'NOT FOUND!';
}
** PHP >= 5.5
simply u can use this
$key = array_search(40489, array_column($userdb, 'uid'));
Let's suppose this multi dimensional array:
$userdb=Array
(
(0) => Array
(
(uid) => '100',
(name) => 'Sandra Shush',
(url) => 'urlof100'
),
(1) => Array
(
(uid) => '5465',
(name) => 'Stefanie Mcmohn',
(pic_square) => 'urlof100'
),
(2) => Array
(
(uid) => '40489',
(name) => 'Michael',
(pic_square) => 'urlof40489'
)
);
$key = array_search(40489, array_column($userdb, 'uid'));
Here is an updated version of Dan Grossman's answer which will cater for multidimensional arrays (what I was after):
function find_key_value($array, $key, $val)
{
foreach ($array as $item)
{
if (is_array($item) && find_key_value($item, $key, $val)) return true;
if (isset($item[$key]) && $item[$key] == $val) return true;
}
return false;
}
If you have to make a lot of "id" lookups and it should be really fast you should use a second array containing all the "ids" as keys:
$lookup_array=array();
foreach($my_array as $arr){
$lookup_array[$arr['id']]=1;
}
Now you can check for an existing id very fast, for example:
echo (isset($lookup_array[152]))?'yes':'no';
A good solution can be one provided by #Elias Van Ootegan in a comment that is:
$ids = array_column($array, 'id', 'id');
echo isset($ids[40489])?"Exist":"Not Exist";
I tried it and worked for me, thanks buddy.
Edited
Note: It will work in PHP 5.5+
TMTOWTDI. Here are several solutions in order of complexity.
(Short primer on complexity follows):O(n) or "big o" means worst case scenario where n means the number of elements in the array, and o(n) or "little o" means best case scenario. Long discrete math story short, you only really have to worry about the worst case scenario, and make sure it's not n ^ 2 or n!. It's more a measure of change in computing time as n increases than it is overall computing time. Wikipedia has a good article about computational aka time complexity.
If experience has taught me anything, it's that spending too much time optimizing your programs' little-o is a distinct waste of time better spent doing something - anything - better.
Solution 0: O(n) / o(1) complexity:
This solution has a best case scenario of 1 comparison - 1 iteration thru the loop, but only provided the matching value is in position 0 of the array. The worst case scenario is it's not in the array, and thus has to iterate over every element of the array.
foreach ($my_array as $sub_array) {
if (#$sub_array['id'] === 152) {
return true;
}
}
return false;
Solution 1: O(n) / o(n) complexity:
This solution must loop thru the entire array no matter where the matching value is, so it's always going to be n iterations thru the array.
return 0 < count(
array_filter(
$my_array,
function ($a) {
return array_key_exists('id', $a) && $a['id'] == 152;
}
)
);
Solution 2: O(n log n) / o(n log n) complexity:
A hash insertion is where the log n comes from; n hash insertions = n * log n. There's a hash lookup at the end which is another log n but it's not included because that's just how discrete math works.
$existence_hash = [];
foreach ($my_array as $sub_array) {
$existence_hash[$sub_array['id']] = true;
}
return #$existence_hash['152'];
I came upon this post looking to do the same and came up with my own solution I wanted to offer for future visitors of this page (and to see if doing this way presents any problems I had not forseen).
If you want to get a simple true or false output and want to do this with one line of code without a function or a loop you could serialize the array and then use stripos to search for the value:
stripos(serialize($my_array),$needle)
It seems to work for me.
As in your question, which is actually a simple 2-D array wouldn't it be better? Have a look-
Let say your 2-D array name $my_array and value to find is $id
function idExists($needle='', $haystack=array()){
//now go through each internal array
foreach ($haystack as $item) {
if ($item['id']===$needle) {
return true;
}
}
return false;
}
and to call it:
idExists($id, $my_array);
As you can see, it actually only check if any internal index with key_name 'id' only, have your $value. Some other answers here might also result true if key_name 'name' also has $value
I don't know if this is better or worse for performance, but here is an alternative:
$keys = array_map(function($element){return $element['id'];}, $my_array);
$flipped_keys = array_flip($keys);
if(isset($flipped_keys[40489]))
{
// true
}
You can create a queue of sub-arrays and loop each:
function existsKeyValue($myArray, $key, $value) {
$queue = [$myArray]; //creating a queue of a single element, which is our outermost array
//when we reach the count of the queue we looped all inner loops as well and failed to find the item
for ($index = 0; $index < count($queue); $index++) {
//Looping the current array, finding the key and the value
foreach ($queue[$index] as $k => &$v) {
//If they match the search, then we can return true
if (($key === $k) && ($value === $v)) {
return true;
}
//We need to make sure we did not already loop our current array to avoid infinite cycles
if (is_array($v)) $queue[]=$v;
}
}
return false;
}
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
echo var_dump(existsKeyValue($my_array, 'id', 152));
array_column returns the values of a single column of an array and we can search for a specific value for those via in_array
if (in_array(152, array_column($my_array, 'id'))) {
echo 'FOUND!';
} else {
echo 'NOT FOUND!';
}
Try with this below code. It should be working fine for any kind of multidimensional array search.
Here you can see LIVE DEMO EXAMPLE
function multi_array_search($search_for, $search_in) {
foreach ($search_in as $element) {
if ( ($element === $search_for) ){
return true;
}elseif(is_array($element)){
$result = multi_array_search($search_for, $element);
if($result == true)
return true;
}
}
return false;
}
You can use this with only two parameter
function whatever($array, $val) {
foreach ($array as $item)
if (isset($item) && in_array($val,$item))
return 1;
return 0;
}
different between isset vs array_key_exits
What's the difference between isset() and array_key_exists()?
different between == vs === How do the PHP equality (== double equals) and identity (=== triple equals) comparison operators differ?
function specificValue(array $array,$key,$val) {
foreach ($array as $item)
if (array_key_exits($item[$key]) && $item[$key] === $val)
return true;
return false;
}
function checkMultiArrayValue($array) {
global $test;
foreach ($array as $key => $item) {
if(!empty($item) && is_array($item)) {
checkMultiArrayValue($item);
}else {
if($item)
$test[$key] = $item;
}
}
return $test;
}
$multiArray = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),);
$test = checkMultiArrayValue($multiArray);
echo "<pre>"
print_r($test);
Will return array who have index and value
I wrote the following function in order to determine if an multidimensional array partially contains a certain value.
function findKeyValue ($array, $needle, $value, $found = false){
foreach ($array as $key => $item){
// Navigate through the array completely.
if (is_array($item)){
$found = $this->findKeyValue($item, $needle, $value, $found);
}
// If the item is a node, verify if the value of the node contains
// the given search parameter. E.G.: 'value' <=> 'This contains the value'
if ( ! empty($key) && $key == $needle && strpos($item, $value) !== false){
return true;
}
}
return $found;
}
Call the function like this:
$this->findKeyValue($array, $key, $value);

How to search by key=>value in a multidimensional array in PHP

Is there any fast way to get all subarrays where a key value pair was found in a multidimensional array? I can't say how deep the array will be.
Simple example array:
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1")
);
When I search for key=name and value="cat 1" the function should return:
array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>3,name=>"cat 1")
);
I guess the function has to be recursive to get down to the deepest level.
Code:
function search($array, $key, $value)
{
$results = array();
if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
$results = array_merge($results, search($subarray, $key, $value));
}
}
return $results;
}
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));
print_r(search($arr, 'name', 'cat 1'));
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => cat 1
)
[1] => Array
(
[id] => 3
[name] => cat 1
)
)
If efficiency is important you could write it so all the recursive calls store their results in the same temporary $results array rather than merging arrays together, like so:
function search($array, $key, $value)
{
$results = array();
search_r($array, $key, $value, $results);
return $results;
}
function search_r($array, $key, $value, &$results)
{
if (!is_array($array)) {
return;
}
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
search_r($subarray, $key, $value, $results);
}
}
The key there is that search_r takes its fourth parameter by reference rather than by value; the ampersand & is crucial.
FYI: If you have an older version of PHP then you have to specify the pass-by-reference part in the call to search_r rather than in its declaration. That is, the last line becomes search_r($subarray, $key, $value, &$results).
How about the SPL version instead? It'll save you some typing:
// I changed your input example to make it harder and
// to show it works at lower depths:
$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
1 => array(array('id'=>3,'name'=>"cat 1")),
2 => array('id'=>2,'name'=>"cat 2")
);
//here's the code:
$arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach ($arrIt as $sub) {
$subArray = $arrIt->getSubIterator();
if ($subArray['name'] === 'cat 1') {
$outputArray[] = iterator_to_array($subArray);
}
}
What's great is that basically the same code will iterate through a directory for you, by using a RecursiveDirectoryIterator instead of a RecursiveArrayIterator. SPL is the roxor.
The only bummer about SPL is that it's badly documented on the web. But several PHP books go into some useful detail, particularly Pro PHP; and you can probably google for more info, too.
<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
1 => array("id"=>2,"name"=>"cat 2"),
2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
return ($ar['name'] == 'cat 1');
//return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});
echo "<pre>";
print_r($arr);
?>
Ref: http://php.net/manual/en/function.array-filter.php
Came back to post this update for anyone needing an optimisation tip on these answers, particulary John Kugelman's great answer up above.
His posted function work fine but I had to optimize this scenario for handling a 12 000 row resultset. The function was taking an eternal 8 secs to go through all records, waaaaaay too long.
I simply needed the function to STOP searching and return when match was found. Ie, if searching for a customer_id, we know we only have one in the resultset and once we find the customer_id in
the multidimensional array, we want to return.
Here is the speed-optimised ( and much simplified ) version of this function, for anyone in need. Unlike other version, it can only handle only one depth of array, does not recurse and does away with merging multiple results.
// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {
foreach ($array as $subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value)
return $subarray;
}
}
This brought down the the task to match the 12 000 records to a 1.5 secs. Still very costly but much more reasonable.
if (isset($array[$key]) && $array[$key] == $value)
A minor imporvement to the fast version.
Here is solution:
<?php
$students['e1003']['birthplace'] = ("Mandaluyong <br>");
$students['ter1003']['birthplace'] = ("San Juan <br>");
$students['fgg1003']['birthplace'] = ("Quezon City <br>");
$students['bdf1003']['birthplace'] = ("Manila <br>");
$key = array_search('Delata Jona', array_column($students, 'name'));
echo $key;
?>
Be careful of linear search algorithms (the above are linear) in multiple dimensional arrays as they have compounded complexity as its depth increases the number of iterations required to traverse the entire array. Eg:
array(
[0] => array ([0] => something, [1] => something_else))
...
[100] => array ([0] => something100, [1] => something_else100))
)
would take at the most 200 iterations to find what you are looking for (if the needle were at [100][1]), with a suitable algorithm.
Linear algorithms in this case perform at O(n) (order total number of elements in entire array), this is poor, a million entries (eg a 1000x100x10 array) would take on average 500,000 iterations to find the needle. Also what would happen if you decided to change the structure of your multidimensional array? And PHP would kick out a recursive algorithm if your depth was more than 100. Computer science can do better:
Where possible, always use objects instead of multiple dimensional arrays:
ArrayObject(
MyObject(something, something_else))
...
MyObject(something100, something_else100))
)
and apply a custom comparator interface and function to sort and find them:
interface Comparable {
public function compareTo(Comparable $o);
}
class MyObject implements Comparable {
public function compareTo(Comparable $o){
...
}
}
function myComp(Comparable $a, Comparable $b){
return $a->compareTo($b);
}
You can use uasort() to utilize a custom comparator, if you're feeling adventurous you should implement your own collections for your objects that can sort and manage them (I always extend ArrayObject to include a search function at the very least).
$arrayObj->uasort("myComp");
Once they are sorted (uasort is O(n log n), which is as good as it gets over arbitrary data), binary search can do the operation in O(log n) time, ie a million entries only takes ~20 iterations to search. As far as I am aware custom comparator binary search is not implemented in PHP (array_search() uses natural ordering which works on object references not their properties), you would have to implement this your self like I do.
This approach is more efficient (there is no longer a depth) and more importantly universal (assuming you enforce comparability using interfaces) since objects define how they are sorted, so you can recycle the code infinitely. Much better =)
$result = array_filter($arr, function ($var) {
$found = false;
array_walk_recursive($var, function ($item, $key) use (&$found) {
$found = $found || $key == "name" && $item == "cat 1";
});
return $found;
});
http://snipplr.com/view/51108/nested-array-search-by-value-or-key/
<?php
//PHP 5.3
function searchNestedArray(array $array, $search, $mode = 'value') {
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
if ($search === ${${"mode"}})
return true;
}
return false;
}
$data = array(
array('abc', 'ddd'),
'ccc',
'bbb',
array('aaa', array('yyy', 'mp' => 555))
);
var_dump(searchNestedArray($data, 555));
function in_multi_array($needle, $key, $haystack)
{
$in_multi_array = false;
if (in_array($needle, $haystack))
{
$in_multi_array = true;
}else
{
foreach( $haystack as $key1 => $val )
{
if(is_array($val))
{
if($this->in_multi_array($needle, $key, $val))
{
$in_multi_array = true;
break;
}
}
}
}
return $in_multi_array;
}
I needed something similar, but to search for multidimensional array by value... I took John example and wrote
function _search_array_by_value($array, $value) {
$results = array();
if (is_array($array)) {
$found = array_search($value,$array);
if ($found) {
$results[] = $found;
}
foreach ($array as $subarray)
$results = array_merge($results, $this->_search_array_by_value($subarray, $value));
}
return $results;
}
I hope it helps somebody :)
This is a revised function from the one that John K. posted... I need to grab only the specific key in the array and nothing above it.
function search_array ( $array, $key, $value )
{
$results = array();
if ( is_array($array) )
{
if ( $array[$key] == $value )
{
$results[] = $array;
} else {
foreach ($array as $subarray)
$results = array_merge( $results, $this->search_array($subarray, $key, $value) );
}
}
return $results;
}
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));
print_r(search_array($arr, 'name', 'cat 1'));
function findKey($tab, $key){
foreach($tab as $k => $value){
if($k==$key) return $value;
if(is_array($value)){
$find = findKey($value, $key);
if($find) return $find;
}
}
return null;
}
I think the easiest way is using php array functions if you know your key.
function search_array ( $array, $key, $value )
{
return array_search($value,array_column($array,$key));
}
this return an index that you could find your desired data by this like below:
$arr = array(0 => array('id' => 1, 'name' => "cat 1"),
1 => array('id' => 2, 'name' => "cat 2"),
2 => array('id' => 3, 'name' => "cat 1")
);
echo json_encode($arr[search_array($arr,'name','cat 2')]);
this output will:
{"id":2,"name":"cat 2"}
And another version that returns the key value from the array element in which the value is found (no recursion, optimized for speed):
// if the array is
$arr['apples'] = array('id' => 1);
$arr['oranges'] = array('id' => 2);
//then
print_r(search_array($arr, 'id', 2);
// returns Array ( [oranges] => Array ( [id] => 2 ) )
// instead of Array ( [0] => Array ( [id] => 2 ) )
// search array for specific key = value
function search_array($array, $key, $value) {
$return = array();
foreach ($array as $k=>$subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value) {
$return[$k] = $subarray;
return $return;
}
}
}
Thanks to all who posted here.
If you want to search for array of keys this is good
function searchKeysInMultiDimensionalArray($array, $keys)
{
$results = array();
if (is_array($array)) {
$resultArray = array_intersect_key($array, array_flip($keys));
if (!empty($resultArray)) {
$results[] = $resultArray;
}
foreach ($array as $subarray) {
$results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
}
}
return $results;
}
Keys will not overwrite because each set of key => values will be in separate array in resulting array.
If you don't want duplicate keys then use this one
function searchKeysInMultiDimensionalArray($array, $keys)
{
$results = array();
if (is_array($array)) {
$resultArray = array_intersect_key($array, array_flip($keys));
if (!empty($resultArray)) {
foreach($resultArray as $key => $single) {
$results[$key] = $single;
}
}
foreach ($array as $subarray) {
$results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
}
}
return $results;
}
2 functions: array_search_key_value which returns the array of keys to reach a key with a value in a multidimensional array, array_extract_keys which returns the value in a multidimensional array pointed to by an array of keys.
function array_search_key_value($array, $key, $value) {
if (!is_array($array)) {
return false;
}
return array_search_key_value_aux($array, $key, $value);
}
function array_search_key_value_aux($array, $key, $value, $path=null) {
if (array_key_exists($key, $array) && $array[$key] === $value) {
$path[]=$key;
return $path;
}
foreach ($array as $k => $v ) {
if (is_array($v)) {
$path[]=$k;
$p = array_search_key_value_aux($v, $key, $value, $path);
if ($p !== false) {
return $p;
}
}
}
return false;
}
function array_extract_keys($array, $key_list) {
$v = $array;
foreach ($key_list as $key) {
if (!is_array($v) || !array_key_exists($key, $v))
return false;
$v = &$v[$key];
}
return $v;
}
Here is a unitary test:
$test_array = array(
'a' => array(
'aa' => true,
'ab' => array(
'aaa' => array(
'one' => 1,
'two' => 2,
'three' => 3,
'four' => 4
),
'four' => 4,
'five' => 5,
),
'six' => 6,
),
'seven' => 7
);
$test_data = array(
array('one', 1),
array('two', 2),
array('three', 3),
array('four', 4),
array('five', 5),
array('six', 6),
array('seven', 7),
array('zero', 0),
array('one', 0),
);
foreach ($test_data as $d) {
$r = array_search_key_value($test_array, $d[0], $d[1]);
echo $d[0] . ' => ' . $d[1] . ' ? ', $r ? implode('/', $r) . ' => ' . array_extract_keys($test_array, $r) : 'null', PHP_EOL;
}

Categories