in_array() not finding needle in haystack - php

I have a simple in_array statement in PHP. It's looking for the this needle:
926296884640412424_1534875699
In this haystack:
Array (
[0] => Array
(
[id] => 926296884640412424_1534875699
)
[1] => Array
(
[id] => 926301883885225094_723729160
)
)
My code is like this:
if(!in_array($object->id, $Admin->hiddenItems, true)) {
// Always fires
} else {
// Never fires
}
And it never finds it. I've tried both with strict set to TRUE and FALSE, but neither works.
What am I doing wrong?

You're searching in a multidimensional array. Flatten it before using in_array():
if (!in_array($object->id, array_column($Admin->hiddenItems, 'id'), true)) {
...
}

<?php
$arrays = array(
array(
'id' => '926296884640412424_1534875699'
),
array(
'id' => '926301883885225094_723729160'
)
);
print exist('926296884640412424_1534875699', $arrays);
function exist($id, $arrays) {
foreach ($arrays as $array) {
if (in_array($id, $array)) {
return "exist";
}
}
return "no exist";
}

You can use this recursive function as well to search certain value in multidimensional arrays:
function multi_in_array_r($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && multi_in_array_r($needle, $element))
return true;
}
return false;
}
It's up to you to decide what gives best results, because as you can see there are few different way to accomplish the same thing.

Related

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

check if array is in two multidimensional array

I have two multidimensional arrays:
Haystack
$haystack = array (
0 => array (
"child_element_id" => 11
"answer_id" => 15
),
1 => array (
"child_element_id" => 12
"answer_id" => 17
),
2 => array (
"child_element_id" => 13
"answer_id" => 21
)
)
Needle
$needle = array (
0 => array (
"child_element_id" => 12
"answer_id" => 17
),
1 => array (
"child_element_id" => 13
"answer_id" => 21
)
)
I want to check if all the key values from array "Needle" exists in the array "Haystack". What's the best practice for this? Thank you!
almost a solution:
#shalvah gave a good starting point. However, in the suggested solution he forgot to loop over the elements of the $needle array like shown below:
function array_in_array($neearr,$haystack) {
foreach ($neearr as $needle){
foreach ($haystack as $array) {
//check arrays for equality
if(count($needle) == count($array)) {
$needleString = serialize($needle);
$arrayString = serialize($array);
echo "$needleString||$arrayString<br>";
if(strcmp($needleString, $arrayString) == 0 ) return true;
}
return false;
}
}
}
But even so is this not completely "water tight". In cases where elements of the "needle" arrays appear in a different order (sequence) the serialze()-function will produce differing strings and will lead to false negatives, like shown in the exampe below:
$hay=array(array('a'=>'car','b'=>'bicycle'),
array('a'=>'bus','b'=>'truck'),
array('a'=>'train','b'=>'coach'));
$nee1=array(array('a'=>'car','b'=>'bicycle'),
array('a'=>'train','b'=>'coach'));
$nee2=array(array('b'=>'bicycle','a'=>'car'), // different order of elements!
array('a'=>'train','b'=>'coach'));
echo array_in_array($nee1,$hay); // true
echo array_in_array($nee2,$hay); // false (but should be true!)
a slightly better solution
This problem can be solved by first sorting (ksort(): sort by key value) all the elements of all the "needle" arrays before serialize-ing them:
function array_in_array($neearr,$haystack) {
$haystackstrarr = array_map(function($array){ksort($array);return serialize($array);},$haystack);
foreach ($neearr as $needle){
ksort($needle);
$needleString = serialize($needle);
foreach ($haystackstrarr as $arrayString){
if(strcmp($needleString, $arrayString) == 0 ) return true;
}
return false;
}
}
echo array_in_array($nee1,$hay); // true
echo array_in_array($nee2,$hay); // true
Pretty easy using in_array() since needle can be an array:
$found = 0;
foreach($needle as $array) {
if(in_array($array, $haystack, true)) {
$found++;
}
}
if($found === count($needle)) {
echo 'all needles were found in haystack';
}
Or maybe:
$found = true;
foreach($needle as $array) {
if(!in_array($array, $haystack, true)) {
$found = false;
break;
}
}
if($found) {
echo 'all needles were found in haystack';
}
You could even use array_search() as you can use an array for needle as well, no need to run two loops.
Using serialize():
if(count(array_map('unserialize',
array_intersect(array_map('serialize', $needle),
array_map('serialize',$haystack)))) == count($needle))
{
echo 'all needles were found in haystack';
}
serialize() the inner arrays of both arrays and compute the intersection (common inner arrays)
unserialize() the result and compare the count() with the count of $needle
You could use this function:
function array_in_array(array $needle, array $haystack) {
foreach($needle as $nearr) {
foreach ($haystack as $array) {
//check arrays for equality
if(count($needle) == count($array)) {
$needleString = serialize($needle);
$arrayString = serialize($array);
if(strcmp($needleString, $arrayString) == 0 )
return true;
}
}
return false;
}

PHP: go through multidimentional array and get array of keys for searched element`s key

I tried to get array of keys of searched element`s key in multidimensional array. For example, my initial array is:
$f['Kitchen']['Dishes']['Mantovarka']=3;
$f['Kitchen']['Dishes']['Castrool']=91;
$f['Kitchen']['Dishes']['Separator']=10;
$f['Kitchen']['Product']=18;
$f['Kitchen']['Textile']=19;
$f['Kitchen']['Blue things One']['Juicemaker']=25;
$f['Kitchen']['Blue things One']['Freegener']=13;
$f['Kitchen']['Blue things']['Microwave']=4;
$f['Kitchen']['Blue things']['Iron']=24;
If I try to get array of keys for 'Separator' key with this function:
$index=0; $array =[];
function getArrayOfkeys($needle, $haystack,$original,$array,$index) {
$index++;
$exists = false;
if(is_array($haystack)){
foreach ($haystack as $key => $val) {
$array[$index]=$key;
if($key == $needle){
$exists = true;
break;
}elseif(is_array($val)){
return getArrayOfkeys($needle, $val,$original,$array,$index);
}
}
}else{
$index--;
}
if($exists==true){
return $array;
}
else{
// I need here logic!!!
}
}
it returns me:
[
1 => 'Kitchen'
2 => 'Dishes'
3 => 'Separator'
]
it is fine!
But when I try to get array of keys of 'Juicemaker' or 'Iron' or 'Product'. It is not working, because I can`t call my getArrayOfkeys() function after element:
$f['Kitchen']['Dishes']['Separator']=10;
How can I call again after abovementioned element?
I want to get for 'Juicemaker' key ['Kitchen', 'Blue things One', 'Juicemaker'].
For 'Product' key ['Kitchen','Product'].
For 'Iron' key ['Kitchen', 'Blue things','Iron']
My function seems to me very unoptimized, help me, please, with optimize it.
Please try this function:
function findKeyPath($arr, $key, $path = '') {
foreach($arr as $k => $value) {
if(is_array($arr[$k])) {
$ret = findKeyPath($arr[$k], $key, $path.$k.',');
if(is_array($ret)) {
return $ret;
}
}else if($k == $key) {
return explode(',', $path.$key);
}
}
return null;
}
print_r(findKeyPath($f, 'Juicemaker'));
//Output: Array ( [0] => Kitchen [1] => Blue things One2 [2] => Juicemaker )
Demo: https://3v4l.org/YJD7q
I hope this will help you.

PHP find value in multidimensional / nested array

I've trawled the site and the net and have tried various recursive functions etc to no avail, so I'm hoping someone here can point out where I'm going wrong :)
I have an array named $meetingArray with the following values;
Array (
[0] => Array (
[Meet_ID] => 9313
[Meet_Name] => 456136
[Meet_CallInNumber] =>
[Meet_AttendeeCode] =>
[Meet_Password] =>
[Meet_ScheduledDateTime] => 2011-07-18 16:00:00
[Meet_ModeratorCode] =>
[Meet_RequireRegistration] => 0
[Meet_CurrentUsers] => 0
)
[1] => Array (
[Meet_ID] => 9314
[Meet_Name] => 456120
[Meet_CallInNumber] =>
[Meet_AttendeeCode] =>
[Meet_Password] =>
[Meet_ScheduledDateTime] => 2011-07-18 16:00:00
[Meet_ModeratorCode] =>
[Meet_RequireRegistration] => 0
[Meet_CurrentUsers] => 0
)
)
I also have a variable named $meetID.
I want to know if the value in $meetID appears in [Meet_Name] within the array and simply evaluate this true or false.
Any help very much appreciated before I shoot myself :)
function multi_in_array($needle, $haystack, $key) {
foreach ($haystack as $h) {
if (array_key_exists($key, $h) && $h[$key]==$needle) {
return true;
}
}
return false;
}
if (multi_in_array($meetID, $meetingArray, 'Meet_Name')) {
//...
}
I am unsure what you mean by
$meetID appears in [Meet_Name]
but simply substitute the $h[$key]==$needle condition with something that meets your needs.
For single-dimensional arrays you can use array_search(). This can be adapted for multi-dimensional arrays like so:
function array_search_recursive($needle, $haystack, $strict=false, $stack=array()) {
$results = array();
foreach($haystack as $key=>$value) {
if(($strict && $needle === $value) || (!$strict && $needle == $value)) {
$results[] = array_merge($stack, array($key));
}
if(is_array($value) && count($value) != 0) {
$results = array_merge($results, array_search_recursive($needle, $value, $strict, array_merge($stack, array($key))));
}
}
return($results);
}
Write a method something like this:
function valInArr($array, $field, $value) {
foreach ($array as $id => $nestedArray) {
if (strpos($value,$nestedArray[$field])) return $id;
//if ($nestedArray[$field] === $value) return $id; // use this line if you want the values to be identical
}
return false;
}
$meetID = 1234;
$x = valInArr($array, "Meet_Name", $meetID);
if ($x) print_r($array[$x]);
This function will evaluate true if the record is found in the array and also enable you to quickly access the specific nested array matching that ID.

How to find an array from parent array?

I am using below code to find an array inside parent array but it is not working that is retuning empty even though the specified key exits in the parent array
$cards_parent = $feedData['BetradarLivescoreData']['Sport']['Category']['Tournament']['Match'];
$cards = array();
foreach($cards_parent as $key => $card)
{
if ($key === 'Cards')
{
$cards[] = $cards_parent[$key];
break;
}
}
Do you know any array function that will search parent array for specified key and if found it will create an array starting from that key?
you want array_key_exists()
takes in a needle (string), then haystack (array) and returns true or false.
in one of the comments, there is a recursive solution that looks like it might be more like what you want. http://us2.php.net/manual/en/function.array-key-exists.php#94601
here you can use recursion:
function Recursor($arr)
{
if(is_array($arr))
{
foreach($arr as $k=>$v)
{
if($k == 'Cards')
{
$_GLOBAL['cards'][] = $card;
} else {
Recursor($arr[$k]);
}
}
}
}
$cards_parent = $feedData['BetradarLivescoreData']['Sport']['Category']['Tournament']['Match'];
$_GLOBAL['cards'] = array();
Recursor($cards_parent);
Could you please put a print_r($feedData) up? I ran the below code
<?php
$feedData = array('BetradarLivescoreData' => array('Sport' => array('Category' => array('Tournament' => array('Match' => array('Cards' => array('hellow','jwalk')))))));
$cards_parent = $feedData['BetradarLivescoreData']['Sport']['Category']['Tournament']['Match'];
$cards = array();
foreach($cards_parent as $key => $card)
{
if ($key === 'Cards')
{
$cards[] = $card;
break;
}
}
print_r($cards);
And it returned a populated array:
Array ( [0] => Array ( [0] => hellow [1] => jwalk ) )
So your code is correct, it may be that your array $feedData is not.

Categories