I've never really used PHP arrays before as I've just used a database in the past so I'm broadening my horizons a little. Basically I have a simple nested array where each element has a 'name' and some other values. I'm trying to search through the array, which is part of an object. I've looked through a number of previous questions on here and can't get it working, although in the other cases there haven't been objects involved. I've been trying to use a 'needle/haystack' type example but haven't got it working yet.
So in my People class we have among other things:
public $peopleArray; // this is the array and will be protected once working
// and this is the example search function im trying to modify
public function findPerson($needle, $haystack)
{
foreach($haystack as $key=>$value)
{
if(is_array($value) && array_search($needle, $value) !== false)
{
return $key;
}
}
return 'false';
}
And then to call this I currently have:
$searchResult = $People->findPerson('Bob',$people->peopleArray,'name');
I'm not sure if I'm just confusing myself with what the $needle and $value - I need to pass the name value in the search function, so I did have $value in the function arguments, but this still returned nothing. Also I'm not 100% on whether '$key=>$value' needs modifying as $key is undefined.
Thanks in advance for any help.
Addition - print_r of the array:
Array ( [0] => Person Object ( [id:protected] => 1 [name] => Bob [gender] => m )
[1] => Person Object ( [id:protected] => 2 [name] => Denise [gender] => f )
[2] => Person Object ( [id:protected] => 3 [name] => Madge [gender] => f ) )
Ok this would be a lot easier if you had to post an example array, but I'm going to give this question a shot.
To me it seems you are looping through a 2D array (nested array).
I would loop through multidimensional arrays like such:
for($array as $key => $2ndArray){
for($2ndArray as $2ndKey => $value){
if($value == $needle){
return true;
}
}
}
Hope this helps
Related
I have two different arrays (say) array1 and array2. I want to check whether a value in array2 exists in array1.
Array1
(
[0] => Array
(
[id] => 7
[title] => Course1
)
[1] => Array
(
[id] => 8
[title] => course2
)
[2] => Array
(
[id] => 9
[title] => course3
)
)
Array2
(
[0] => 7
[1] => 8
)
I used:
foreach ($array2 as $id) {
$found = current(array_filter($array1, function($item) {
return isset($item['id']) && ($id == $item['id']);
}));
print_r($found);
}
When I run this code it give the following error:
Undefined variable: id
The reason for your error is that you are trying to use a variable within your anonymous function that is not available to it. Have a read of the relevant PHP documentation (esp. Example #3) to make sure you are clear on what I'm talking about.
In brief, your variable $id is declared in the parent scope of your closure (or anonymous function). In order for it to be available within your closure you must make it available via the use statement.
If you change the key line of your code to be:
$found = current(array_filter($array1, function($item) use ($id) {
your program should work as expected.
Here is simple code as per your question :
foreach($array2 as $id){
return in_array($id, array_column($array1, 'id'));
}
Make sure this is a useful to you.
I am trying to remove records from a multidimensional array if certain criteria are met. The condition is that the element 'cap' should only have 'Capped' or Uncapped', if 'Other' is there, it should be removed from the array.
I have tried using Unset() but with no luck. It does not break the code, but it changes nothing. Output of the array:
[0] => Array
(
[name] => Club Name
[speed] => Annual Membership
[cap] => Other
[s_description] => Short description
[l_description] => Long description
)
[1] => Array
(
[name] => 50\5Mbps Fibre with 250GB
[speed] => Residential 50/5 Capped
[cap] => Capped
[s_description] => Short description
[l_description] => Long description
)
[2] => Array
(
[name] => FB-FP-B-V-50/5MBPS-400-24
[speed] => Residential 50/5 Capped
[cap] => Capped
[s_description] => Short description
[l_description] => Long description
)
Code for removing the 'Other' record:
foreach ($product_details['cap'] as $key ->$val_test) {
if ($val_test == "Other") {
unset($product_details[$key]);
}
}
I realise I may be doing something really stupid, but for something that should be fairly simple, it seems really difficult!
Thanks
Assuming your main array is stored under the variable: $product_details
Your code would be
foreach($product_details as $key => $product){
if($product['cap'] == "Other"){
unset($product_details[$key]);
}
}
You cant loop over '$product_details['cap']' as that is part of your inner array.
You must loop over your outer array then check the value of the inner array.
I hope this makes sense.
EDIT: On rereading of your question you could change your if statement to this to make it more open ended;
if($product['cap'] != "Capped" && $product['cap'] != "Uncapped"){
My solution
foreach ($your_array as $element) {
if ($element['cap'] == "Other") {
continue;
} else {
$newarray[] = $element;
}
}
$a1=array("a"=>"red","b"=>"green","c"=>"blue","d"=>"yellow");
$a2=array("e"=>"red","f"=>"green","g"=>"blue");
$result=array_diff($a1,$a2);
Else you have to loop like above. There are other methods to map as well.
Most likely I'm doing this wayyyyyy too complicated. But I'm in the need of converting multiple arrays to multidimensional array key's. So arrays like this:
Array //$original
(
[0] => 500034
[1] => 500035 //these values need to become
//consecutive keys, in order of array
)
Needs to become:
Array
(
[50034][50035] => array()
)
This needs to be done recursively, as it might also require that it becomes deeper:
Array
(
[50034][50036][50126] => array() //notice that the numbers
//aren't necessarily consecutive, though they are
//in the order of the original array
)
My current code:
$new_array = array();
foreach($original as $k => $v){ //$original from first code
if((gettype($v) === 'string' || gettype($v) === 'integer')
&& !array_key_exists($v, $original)){ //check so as to not have illigal offset types
$new_array =& $original[array_search($v, $original)];
echo 'In loop: <br />';
var_dump($new_array);
echo '<br />';
}
}
echo "After loop <br />";
var_dump($new_array);
echo "</pre><br />";
Gives me:
In loop:
int(500032)
In loop:
int(500033)
After loop
int(500033)
Using this code $new_array =& $original[array_search($v, $original)]; I expected After loop: $new_array[50034][50035] => array().
What am I doing wrong? Been at this for hours on end now :(
EDIT to answer "why" I'm trying to do this
I'm reconstructing facebook data out of a database. Below is my own personal data that isn't reconstructing properly, which is why I need the above question answered.
[500226] => Array
(
[own_id] =>
[entity] => Work
[name] => Office Products Depot
[500227] => Array
(
[own_id] => 500226
[entity] => Employer
[id] => 635872699779885
)
[id] => 646422765379085
)
[500227] => Array
(
[500228] => Array
(
[own_id] => 500227
[entity] => Position
[id] => 140103209354647
)
[name] => Junior Programmer
)
As you can see, the ID [500227] is a child of [500226], however, because I haven't got the path to the child array, a new array is created. The current parentage only works to the first level.
[own_id] is a key where the value indicates which other key should be its parent. Which is why the first array ([500226]) doesn't have a value for [own_id].
If you want to do something recursively, do it recursively. I hope that's what you meant to do.
public function pivotArray($array, $newArray)
{
$shifted = array_shift($array);
if( $shifted !== null )
{
return $this->pivotArray($array, array($shifted=>$newArray));
}
return $newArray;
}
$array = array(432, 432532, 564364);
$newArray = $this->pivotArray($array, array());
Edit: After the question's edit it doesn't seem to be very relevant. Well, maybe someone will find it useful anyway.
I have a recursive array search function which has previously been working a treat. For some reason though now it appears to be telling me things exist in the array which actually don't.
IE, I have an array like this
Array
(
[0] => Array
(
[name] => people
[groups] => Array
(
[0] => Array
(
[name] => tom
)
[1] => Array
(
[name] => john
)
)
)
)
And my recursive search function:
function searchArrayRecursive($needle, $haystack){
foreach ($haystack as $key => $arr) {
if(is_array($arr)) {
$ret=searchArrayRecursive($needle, $arr);
if($ret!=-1) return $key.','.$ret;
} else {
if($arr == $needle) return (string)$key;
}
}
return -1;
}
If I were to do the following however:
$search = searchArrayRecursive('kim',$the_array);
if($search != -1) {
echo 'result: found<br />';
} else {
echo 'result: not found';
}
I get result: found
Its clearly not in the array. Maybe my function never worked. maybe my heads on backwards. Any ideass?
note: I also get result: found when I search for tom or john o.O
This example works as provided. Possibly your actual data has mixed case? ('john' != 'John') or possibly extra spaces or a stray newline because they weren't trimmed when the array was created?
Try a var_dump() instead of a print_r(). It should show you the exact nature of the data you are trying to search. I suspect your data may not be in the format you expect it to be.
I know there are a lot of answers on multi-dimensional arrays but I couldn't find what I was looking for exactly. I'm new to PHP and can't quite get my head around some of the other examples to modify them. If someone could show me the way, it would be much appreciated.
An external service is passing me the following multidimensional array.
$mArray = Array (
[success] => 1
[errors] => 0
[data] => Array (
[0] => Array (
[email] => me#example.com
[id] => 123456
[email_type] => html
[ip_opt] => 10.10.1.1
[ip_signup] =>
[member_rating] => X
[info_changed] => 2011-08-17 08:56:51
[web_id] => 123456789
[language] =>
[merges] => Array (
[EMAIL] => me#example.com
[NAME] => Firstname
[LNAME] => Lastname
[ACCOUNT] => ACME Ltd
[ACCMANID] => 123456adc
[ACCMANTEL] => 1234 123456
[ACCMANMAIL] => an.other#example.com
[ACCMANFN] => Humpty
[ACCMANLN] => Dumpty
)
[status] => unknown
[timestamp] => 2011-08-17 08:56:51
[lists] => Array ( )
[geo] => Array ( )
[clients] => Array ( )
[static_segments] => Array ( )
)
)
)
The only information I'm interested in are the key/value pairs that are held in the array under the key name 'merges'. It's about the third array deep. The key name of the array will always be called merges but there's no guarantee that its location in the array won't be moved. The number of key/value pairs in the merges array is also changeable.
I think what I need is a function for array_walk_recursive($mArray, "myfunction", $search);, where $search holds the string for the Key name (merges) I'm looking for. It needs to walk the array until it finds the key, check that it holds an array and then (preserving the keys), return each key/value pair into a single array.
So, for clarity, the output of the function would return:
$sArray = Array (
[EMAIL] => me#example.com
[NAME] => Firstname
[LNAME] => Lastname
[ACCOUNT] => ACME Ltd
[ACCMANID] => 123456adc
[ACCMANTEL] => 1234 123456
[ACCMANMAIL] => an.other#example.com
[ACCMANFN] => Humpty
[ACCMANLN] => Dumpty
)
I can then move on to the next step in my project, which is to compare the keys in the single merges array to element IDs obtained from an HTML DOM Parser and replace the attribute values with those contained in the single array.
I probably need a foreach loop. I know I can use is_array to verify if $search is an array. It's joining it all together that I'm struggling with.
Thanks for your help.
Would this work?
function find_merges($arr)
{
foreach($arr as $key => $value){
if($key == "merges") return $value;
if(is_array($value)){
$ret = find_merges($value);
if($ret) return $ret;
}
}
return false;
}
It would do a depth-first search until you either ran out of keys or found one with the value merges. It won't check to see if merges is an array though. Try that and let me know if that works.
Here is a general purpose function that will work it's way through a nested array and return the value associated with the first occurance of the supplied key. It allows for integer or string keys. If no matching key is found it returns false.
// return the value a key in the supplied array
function get_keyval($arr,$mykey)
{
foreach($arr as $key => $value){
if((gettype($key) == gettype($mykey)) && ($key == $mykey)) {
return $value;
}
if(is_array($value)){
return get_keyval($value,$mykey);
}
}
return false;
}
// test it out
$myArray = get_keyval($suppliedArray, "merges");
foreach($myArray as $key => $value){
echo "$key = $value\n";
}
A recursive function can do this. Returns the array or FALSE on failure.
function search_sub_array ($array, $search = 'merges') {
if (!is_array($array)) return FALSE; // We're not interested in non-arrays
foreach ($array as $key => $val) { // loop through array elements
if (is_array($val)) { // We're still not interested in non-arrays
if ($key == $search) {
return $val; // We found it, return it
} else if (($result = search_sub_array($array)) !== FALSE) { // We found a sub-array, search that as well
return $result; // We found it, return it
}
}
}
return FALSE; // We didn't find it
}
// Example usage
if (($result = search_sub_array($myArray,'merges')) !== FALSE) {
echo "I found it! ".print_r($result,TRUE);
} else {
echo "I didn't find it :-(";
}
So you want to access an array within an array within an array?
$mergeArray = NULL;
foreach($mArray['data'] as $mmArray)
$mergeArray[] = $mmArray['merges'];
Something like that? If merges is always three deep down, I don't see why you need recursion. Otherwise see the other answers.
Here's another approach, mostly because I haven't used up my iterator quota yet today.
$search = new RegexIterator(
new RecursiveIteratorIterator(
new ParentIterator(new RecursiveArrayIterator($array)),
RecursiveIteratorIterator::SELF_FIRST),
'/^merges$/D', RegexIterator::MATCH, RegexIterator::USE_KEY
);
$search->rewind();
$merges = $search->current();
array_walk_recursive() is brilliant for this task! It doesn't care what level the key-value pairs are on and it only iterates the "leaf nodes" so there is not need to check if an element contains a string. Inside of the function, I am merely making a comparison on keys versus the array of needles to generate a one-dimensional result array ($sArray).
To be clear, I am making an assumption that you have predictable keys in your merges subarray.
Code: (Demo)
$needles=['EMAIL','NAME','LNAME','ACCOUNT','ACCMANID','ACCMANTEL','ACCMANMAIL','ACCMANFN','ACCMANLN'];
array_walk_recursive($mArray,function($v,$k)use(&$sArray,$needles){if(in_array($k,$needles))$sArray[$k]=$v;});
var_export($sArray);
Output:
array (
'EMAIL' => 'me#example.com',
'NAME' => 'Firstname',
'LNAME' => 'Lastname',
'ACCOUNT' => 'ACME Ltd',
'ACCMANID' => '123456adc',
'ACCMANTEL' => '1234 123456',
'ACCMANMAIL' => 'an.other#example.com',
'ACCMANFN' => 'Humpty',
'ACCMANLN' => 'Dumpty',
)