PHP: Find element with certain property value in array - php

I'm sure there is an easy way to do this, but I can't think of it right now. Is there an array function or something that lets me search through an array and find the item that has a certain property value? For example:
$people = array(
array(
'name' => 'Alice',
'age' => 25,
),
array(
'name' => 'Waldo',
'age' => 89,
),
array(
'name' => 'Bob',
'age' => 27,
),
);
How can I find and get Waldo?

With the following snippet you have a general idea how to do it:
foreach ($people as $i => $person)
{
if (array_key_exists('name', $person) && $person['name'] == 'Waldo')
echo('Waldo found at ' . $i);
}
Then you can make the previous snippet as a general use function like:
function SearchArray($array, $searchIndex, $searchValue)
{
if (!is_array($array) || $searchIndex == '')
return false;
foreach ($array as $k => $v)
{
if (is_array($v) && array_key_exists($searchIndex, $v) && $v[$searchIndex] == $searchValue)
return $k;
}
return false;
}
And use it like this:
$foundIndex = SearchArray($people, 'name', 'Waldo'); //Search by name
$foundIndex = SearchArray($people, 'age', 89); //Search by age
But watch out as the function can return 0 and false which both evaluates to false (use something like if ($foundIndex !== false) or if ($foundIndex === false)).

function findByName($array, $name) {
foreach ($array as $person) {
if ($person['name'] == $name) {
return $person;
}
}
}

function getCustomSearch($key) {
foreach($people as $p) {
if($p['name']==$searchKey) return $p
}
}
getCustomSearch('waldo');

Related

How to transform many array to 1 standard?

i have many api service with response
[
'brand_name' => Adidas,
'item_count' => 24
]
and
[
'brand_name' => Nike,
'count_item' => 254
]
and
[
'name' => Reebok,
'count_all' => 342
]
how to transform it to 1 standard? oop please
['brand' => $value, 'cnt' = $count]
If they are in the same order, just combine your keys with the values:
$array = array_combine(['brand', 'cnt'], array_values($array));
If not, just match and replace:
$array = array_combine(
preg_replace(['/.*name.*/', '/.*count.*/'], ['brand', 'cnt'], array_keys($array)),
$array);
If it could be brand, name or brand_name, etc. Then use an OR |:
/.*(name|brand).*/
If you know all of the possible combinations, then:
$replace = ['brand_name' => 'brand', 'name' => 'brand',
'item_count' => 'cnt', 'count_item' => 'cnt', 'count_all' => 'cnt'];
$array = array_combine(str_replace(array_keys($replace), $replace, array_keys($array)),
$array);
One of these should get you on the right path.
To transform many array into one standard like above, you need to think of common criteria that can apply to all arrays. In your case, I can see that all arrays have 2 keys, with the first keys contain a word "name" so I can use it as a criterion for "brand". Then there is second keys contain a word "count" used as a criterion for "cnt".
$new_array = [];
foreach($array as $item) {
$brand = '';
$cnt = '';
foreach($item as $key => $value) {
if(strpos($key, 'name') !== false) {
$brand = $value;
}
elseif(strpos($key, 'count') !== false) {
$cnt = $value;
}
// more conditions
}
$new_array[] = ['brand' => $brand, 'cnt' => $cnt];
}
Suppose you have another array:
[
'brand' => 'Danbo',
'total' => 200,
]
Since this is an exception, you need to make another condition:
elseif(strpos($key, 'brand') !== false) {
$brand = $value;
}
elseif(strpos($key, 'total') !== false) {
$cnt = $value;
}
or append to existing conditions:
if(strpos($key, 'name') !== false || strpos($key, 'brand') !== false) {
$brand = $value;
}
elseif(strpos($key, 'count') !== false || strpos($key, 'total') !== false) {
$cnt = $value;
}

Trying to write a function for search a value in an array, relying on references in child elements

How can I achieve this behavior??
I've tried to write a function to implement this logic, but for some reason it does not work.
Here is the link that I tried to do http://sandbox.onlinephpfunctions.com/code/638fc7796a8918e2b7ef1469b746c29adba8d0cd
<?php
$test = [
'deepLink' => [
1,2,3,4,5, 'testMe'
],
'base' => [ // child for (2 and target)
'SuperMan',
'deepLink' // expected true, if we call array_search_for_target_key($test, 'target', 'testMe')
],
2 => [
'base' // link on child (base)
],
'target' => [
2 // link on child (2)
],
];
function array_search_for_target_key($array = array(), $targetKkey, $search) {
$res = false;
foreach($array as $k => $v) {
if ($k === $targetKkey && in_array($search, $v)) {
$res = true;
} else {
if (is_array($v)) {
foreach ($v as $nested) {
$array = $nested;
$res = array_search_for_target_key($array, $nested, $search);
}
}
}
}
return $res;
}
var_dump( array_search_for_target_key($test, 'target', 'SuperMan'));
So i soleved my problem, here the
link
You are getting error in this part
$array = $nested;
$res = array_search_for_target_key($array, $nested, $search);
The $array is not an array so it throws an error. Which is
Invalid argument supplied for foreach()
So Change your code from this:
foreach ($v as $nested){
$array = $nested;
$res = array_search_for_target_key($array, $nested, $search);
}
With this
foreach ($v as $nested) {
$res = array_search_for_target_key($v, $nested, $search);
}
After changing that we will encounter a new error
in_array() expects parameter 2 to be array, integer given
To fix this we need to check if the variable is an array.
Change your code from this:
if ($k === $targetKkey && in_array($search, $v))
With this
if ($k === $targetKkey && is_array($v) && in_array($search, $v))
Also in your:
if ($k === $targetKkey && is_array($v) && in_array($search, $v)) {
$res = true;
}
Change $res = true to return true;.
We don't want to continue if we already found the target.
Change $k === $targetKkey to $k == $targetKkey. 2 === '2' will return false so change it to ==
Here is the Whole Code
<?php
$test = [
'deepLink' => [
1,2,3,4,5, 'testMe'
],
'base' => [ // child for (2 and target)
'SuperMan',
'deepLink' // expected true, if we call array_search_for_target_key($test, 'target', 'testMe')
],
2 => [
'base' // link on child (base)
],
'target' => [
2 // link on child (2)
],
];
function array_search_for_target_key($array, $targetKkey, $search) {
$res = false;
foreach($array as $k => $v) {
if ($k == $targetKkey && is_array($v) && in_array($search, $v)) {
return true;
} else {
if (is_array($v)) {
foreach ($v as $nested) {
$res = array_search_for_target_key($v, $nested, $search);
}
}
}
}
return $res;
}
var_dump( array_search_for_target_key($test, 'target', 'SuperMan'));
Test here

Dynamically dig into JSON with PHP

Okay, so I need to dynamically dig into a JSON structure with PHP and I don't even know if it is possible.
So, let's say that my JSON is stored ad the variable $data:
$data = {
'actions':{
'bla': 'value_actionBla',
'blo': 'value_actionBlo',
}
}
So, to access the value of value_actionsBla, I just do $data['actions']['bla']. Simple enough.
My JSON is dynamically generated, and the next time, it is like this:
$data = {
'actions':{
'bla': 'value_actionBla',
'blo': 'value_actionBlo',
'bli':{
'new': 'value_new'
}
}
}
Once again, to get the new_value, I do: $data['actions']['bli']['new'].
I guess you see the issue.
If I need to dig two levels, then I need to write $data['first_level']['second_level'], with three, it will be $data['first_level']['second_level']['third_level'] and so on ...
Is there any way to perform such actions dynamically? (given I know the keys)
EDIT_0: Here is an example of how I do it so far (in a not dynamic way, with 2 levels)
// For example, assert that 'value_actionsBla' == $data['actions']['bla']
foreach($data as $expected => $value) {
$this->assertEquals($expected, $data[$value[0]][$value[1]]);
}
EDIT_1
I have made a recursive function to do it, based on the solution of #Matei Mihai:
private function _isValueWhereItSupposedToBe($supposedPlace, $value, $data){
foreach ($supposedPlace as $index => $item) {
if(($data = $data[$item]) == $value)
return true;
if(is_array($item))
$this->_isValueWhereItSupposedToBe($item, $value, $data);
}
return false;
}
public function testValue(){
$searched = 'Found';
$data = array(
'actions' => array(
'abort' => '/abort',
'next' => '/next'
),
'form' => array(
'title' => 'Found'
)
);
$this->assertTrue($this->_isValueWhereItSupposedToBe(array('form', 'title'), $searched, $data));
}
You can use a recursive function:
function array_search_by_key_recursive($needle, $haystack)
{
foreach ($haystack as $key => $value) {
if ($key === $needle) {
return $value;
}
if (is_array($value) && ($result = array_search_by_key_recursive($needle, $value)) !== false) {
return $result;
}
}
return false;
}
$arr = ['test' => 'test', 'test1' => ['test2' => 'test2']];
var_dump(array_search_by_key_recursive('test2', $arr));
The result is string(5) "test2"
You could use a function like this to traverse down an array recursively (given you know all the keys for the value you want to access!):
function array_get_nested_value($data, array $keys) {
if (empty($keys)) {
return $data;
}
$current = array_shift($keys);
if (!is_array($data) || !isset($data[$current])) {
// key does not exist or $data does not contain an array
// you could also throw an exception here
return null;
}
return array_get_nested_value($data[$current], $keys);
}
Use it like this:
$array = [
'test1' => [
'foo' => [
'hello' => 123
]
],
'test2' => 'bar'
];
array_get_nested_value($array, ['test1', 'foo', 'hello']); // will return 123

Recursive search return all keys where value is present

Currently stuck trying to get the last part working, wanting to get all array keys returned where the value exists.
Test data
$testArr = array(
'id' => '249653315914',
'title' => 'testing',
'description' => 'testing',
'usernames' => array('jake', 'liam', 'john'),
'masterNames' => array('jake'),
'data' => array(
'aliases' => array(
'jake'
)
)
);
Method
recursive_search('jake', $testArr);
function recursive_search($needle, $haystack, $child = false) {
$values = array();
foreach($haystack as $key => $value) {
$current_key = $key;
if($needle === $value OR (is_array($value) && $children = recursive_search($needle, $value, true) !== false)) {
if($child) {
if($needle == $value) {
return true;
}
echo "children: $child, current_key: $current_key ";
return $current_key;
}
echo "current_key: $current_key, key: $key <br>";
$values[] = $current_key;
}
}
if(!empty($values)) {
return $values;
}
return false;
}
Output
current_key: usernames, key: usernames
current_key: masterNames, key: masterNames
children: 1, current_key: aliases current_key: data, key: data
array (size=3)
0 => string 'usernames' (length=5)
1 => string 'masterNames' (length=8)
2 => string 'data' (length=4)
Expected
array(
'usernames',
'masterNames',
'data' => array('aliases')
)
I'm losing track on the $child part I think, somewhere I should be returning something and assigning it but I think I've looked at this to long and overlooking the obvious.
Any help is awesome.
$testArr = array(
'id' => '249653315914',
'title' => 'jake',
'description' => 'testing',
'usernames' => array('jake', 'liam', 'john'),
'masterNames' => array('jake'),
'data' => array(
'aliases' => array(
'jake'
),
'aliases2' => array('level3' => array('jake'))
)
);
function recursive_search($needle, $haystack) {
$return = array();
if (is_array($haystack))
foreach($haystack as $key => $value)
{
if (is_array($value))
{
$child = recursive_search($needle, $value);
if (is_array($child) && !empty($child))
$return = array_merge($return, array($key => $child));
elseif ($child) $return[] = $key;
}
elseif ($value === $needle)
if (is_integer($key))
return true;
else
$return[] = $key;
}
elseif ($haystack === $needle)
return true;
return $return;
}
Output
Array
(
[0] => title
[1] => usernames
[2] => masterNames
[data] => Array
(
[0] => aliases
[aliases2] => Array
(
[0] => level3
)
)
)
Testing is needed, no warranty that it will work in all cases. Also, in the cases like this array('level3' => array('jake'), 'jake'), it will not go deeper to level3 and so on, as 'jake' is present in the original array. Please mention if that is not a desired behavior.
Edit by Bankzilla: To work with objects
function recursive_search($needle, $haystack) {
$return = array();
if (is_array($haystack) || is_object($haystack)) {
foreach($haystack as $key => $value) {
if (is_array($value) || is_object($value)) {
$child = recursive_search($needle, $value);
if ((is_array($child) || is_object($child)) && !empty($child)) {
$return = array_merge($return, array($key => $child));
} elseif ($child) {
$return[] = $key;
}
}
elseif ($value === $needle) {
if (is_integer($key)) {
return true;
} else {
$return[] = $key;
}
}
}
} elseif ($haystack === $needle) {
return true;
}
return $return;
}
the things I thought you did wrong was checking for if current $value is an array and doing a recursive search on it, while doing nothing with the return value of it (which should be the array either false ) , here I used a more step by step approach (well at least I thought so )
this works for a "tree with more branches"
EDIT
function recursive_search($needle, $haystack) {
$values = array();
foreach($haystack as $key => $value) {
if(is_array($value)) {
$children = $this->recursive_search($needle, $value);
if($children !== false){
if(!is_bool($children) and !empty($children)){
$key = array($key => $children);
}
$values[] = $key;
}
} else if(strcmp($needle, $value) == 0 ){
if(is_int($key))
return true;
else
$vaues[] = $key;
}
}
if(!empty($values)) {
return $values;
}
return false;
}
got rid of the "0"s in the array, thx Cheery for the hint (from his response)

PHP - Arrays and Foreach

I searched in Google and consulted the PHP documentation, but couldn't figure out how the following code works:
$some='name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
return $addons;
}
echo (count( getActiveAddons( $some ) ) ? implode( '<br />', getActiveAddons( $some ) ) : 'None');
The code always echo's None.
Please help me in this.
I don't know where you got this code from but you've initialized $some the wrong way. It is expected as an array like this:
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon'
'nextduedate' => '2013-04-11',
'status' => 'Active'
)
);
I guess the article you've read is expecting you to parse the original string into this format.
You can achieve this like this:
$string = 'name=Licensing Module;nextduedate=2013-04-10;status=Active|name=Test Addon;nextduedate=2013-04-11;status=Active';
$result = array();
foreach(explode('|', $string) as $record) {
$item = array();
foreach(explode(';', $record) as $column) {
$keyval = explode('=', $column);
$item[$keyval[0]] = $keyval[1];
}
$result[]= $item;
}
// now call your function
getActiveAddons($result);
$some is not an array so foreach will not operate on it. You need to do something like
$some = array(
array(
'name' => 'Licensing Module',
'nextduedate' => '2013-04-10',
'status' => 'Active'
),
array(
'name' => 'Test Addon',
'nextduedate' => '2013-04-11',
'status'=> 'Active'
)
);
This will create a multidimensional array that you can loop through.
function getActiveAddons($somet) {
$addons = array( );
foreach ($somet as $addon) {
foreach($addon as $key => $value) {
if ($key == 'status' && $value == 'Active') {
$addons[] = $addon['name'];
continue;
}
}
}
return $addons;
}
First, your $some variable is just a string. You could parse the string into an array using explode(), but it's easier to just start as an array:
$some = array(
array(
"name" => "Licensing Module",
"nextduedate" => "2013-04-10",
"status" => "Active",
),
array(
"name" => "Test Addon",
"nextduedate" => "2013-04-11",
"status" => "Active",
)
);
Now, for your function, you are on the right track, but I'll just clean it up:
function getActiveAddons($somet) {
if (!is_array($somet)) {
return false;
}
$addons = array();
foreach ($somet as $addon) {
if ($addon['status'] == 'Active') {
$addons[] = $addon['name'];
}
}
if (count($addons) > 0) {
return $addons;
}
return false;
}
And finally your output (you were calling the function twice):
$result = getActiveAddons($some);
if ($result === false) {
echo "No active addons!";
}
else {
echo implode("<br />", $result);
}

Categories