Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Given the following haystack and needle:

$haystack = array(
  'foo' => array(
    1 => 'one',
    2 => 'two',
    3 => 'three',
  ),
);

$needle = array(
  'foo' => array(
    1 => 'one',
    2 => 'two',
  ),
);

I want to check if all nested key-value pairs of the needle occur in the haystack (like it does in the example above), while ignoring any additional key-value pairs that may exist in the haystack (like $haystack['foo'][3] in the example).

There are many similar questions on SO but I haven't found a solution for this specific use case. Is there a (combination of) standard PHP functions to do this? What is the most elegant solution?

[update]

I didn't make clear yet that the arrays may not always have the same depth. Also, the keys of the elements in the arrays may be different every time.

share|improve this question
1  
You should show what you've tried. I have an answer posted but deleted as I prefer to answer questions that show effort. –  John Conde Mar 6 at 16:03
    
So, you want to check if $needle is inside $haystack ?? –  samaYo Mar 6 at 16:03
    
@JohnConde I know, I'll post what I came up with as an answer. –  marcvangend Mar 6 at 16:07
    
@sam_io yes, that is what I want to know, taking all nested levels of both arrays into account. –  marcvangend Mar 6 at 16:08
    
@marcvangend I tried :/ sadly it's too tricky, and me got no time. It is quite interesting challenge. good luck :) +1 for the question. –  samaYo Mar 6 at 16:59

2 Answers 2

array_intersect() will tell you what values match. Just make sure that matches your $needle.

echo $needle['foo'] === array_intersect($needle['foo'], $haystack['foo']);
share|improve this answer
    
If I'm not mistaken, this will only work with arrays that are one level deep, right? –  marcvangend Mar 6 at 16:09
    
If I change the values I still get a match. –  Jay Blanchard Mar 6 at 16:12
    
My updated answer solves that problem –  John Conde Mar 6 at 16:14
1  
If it is a nested array than this won't work and there is no "elegant" way to do this. The array key can obviously be dynamic in your code. –  John Conde Mar 6 at 16:27
1  
I think this is doable as the OP requested, but not without less than at-least 10 lines of code. However, this answer does not enable dynamic keys, or more depth. –  samaYo Mar 6 at 16:29
up vote 0 down vote accepted

This is what I came up with myself. It works, but it seems more complex than it should be...

/**
 * Helper function which recursively checks if the key-value pairs in one array
 * are all present in another array. If all key-value pairs in the needle are
 * present in the haystack, and the haystack also contains additional items,
 * the check wil still pass.
 *
 * @param array $needle
 *   The array with the key-value pairs to look for.
 * @param array $haystack
 *   The array in which to look for the key-value pairs.
 * @return bool
 *   TRUE if all key-value pairs of the needle occur in the haystack. FALSE if
 *   one or more keys or values are missing or different.
 */
function array_contains(array $needle, array $haystack) {
  // First, check if needle and haystack are identical. In that case it's easy.
  if ($needle === $haystack) {
    return TRUE;
  }
  foreach ($needle as $key => $value) {
    // If the key does not occur in the haystack, we're done.
    if (!isset($haystack[$key])) {
      return FALSE;
    }
    // If the value is an array...
    if (is_array($value)) {
      // ...see if the counterpart in $haystack is an array too...
      if (!is_array($haystack[$key])) {
        return FALSE;
      }
      // ...and if so, recurse.
      if (array_contains($value, $haystack[$key]) == FALSE) {
        return FALSE;
      }
    }
    // If the values are not arrays and not the same, the check fails.
    else if ($value != $haystack[$key]) {
      return FALSE;
    }
  }
  // If we still didn't fail, all tests have passed.
  return TRUE;
}
share|improve this answer
    
Modify your OP to add this. –  Jay Blanchard Mar 6 at 16:13
    
See my updated answer. It's a oneliner and works. –  John Conde Mar 6 at 16:14
    
@JayBlanchard I have been criticized by mods before for including a possible answer in my question, telling me that is should be an answer instead... –  marcvangend Mar 6 at 16:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.