94

I have an array that looks like this:

array(
  'abc' => 0,
  'foo-bcd' => 1,
  'foo-def' => 1,
  'foo-xyz' => 0,
  // ...
)

How can I retain only the elements that start with foo-?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Alex
  • 66,732
  • 177
  • 439
  • 641
  • 3
    Having an array with prefixes like this is a code smell. Extract those values into an object holding these values or at least make the prefix point to an array and add the values to it. – Gordon Feb 12 '11 at 17:29
  • **See also:** https://stackoverflow.com/questions/13766898/php-get-array-values-of-a-string-array-that-match-substrings-of-another-string – dreftymac Oct 15 '19 at 04:03

10 Answers10

151

Functional approach:

$array = array_filter($array, function($key) {
    return strpos($key, 'foo-') === 0;
}, ARRAY_FILTER_USE_KEY);

Procedural approach:

$only_foo = array();
foreach ($array as $key => $value) {
    if (strpos($key, 'foo-') === 0) {
        $only_foo[$key] = $value;
    }
}

Procedural approach using objects:

$i = new ArrayIterator($array);
$only_foo = array();
while ($i->valid()) {
    if (strpos($i->key(), 'foo-') === 0) {
        $only_foo[$i->key()] = $i->current();
    }
    $i->next();
}
Black
  • 18,150
  • 39
  • 158
  • 271
erisco
  • 14,154
  • 2
  • 40
  • 45
  • 21
    Note PHP 5.6 adds the ARRAY_FILTER_USE_KEY flag to `array_filter()`, which you can use instead of supplying a custom `array_filter_key()` function. – Jason Sep 09 '15 at 11:44
  • 5
    Can you please just add the array_filter_key function to your example? I kept getting an error and had to re-read your post multiple times before recognizing my mistake. It's not hard to just post the code, save a click, and save somebody time troubleshooting. Thanks. – Chris Sprague Sep 04 '18 at 07:14
  • This answer will be fooling a lot of researchers and wasting their time until they realize that `array_filter_key()` is not a native function. Researchers shouldn't have to link-chase to receive the whole solution. – mickmackusa Jan 19 '21 at 21:29
  • With php8 you can also use `str_starts_with($key, 'foo-')` – Tofandel Mar 29 '23 at 11:49
38

This is how I would do it, though I can't give you a more efficient advice before understanding what you want to do with the values you get.

$search = "foo-";
$search_length = strlen($search);
foreach ($array as $key => $value) {
    if (substr($key, 0, $search_length) == $search) {
        ...use the $value...
    }
}
Matías Cánepa
  • 5,770
  • 4
  • 57
  • 97
  • 2
    You also can use: `foreach ($array as $key => $value) { if (0 === strpos($key, 'foo-')) { ...use the $value... } }` – Iago Mar 02 '15 at 19:06
  • The "4" here needs to be adjusted to whatever length "foo-" is. – Jason Sep 09 '15 at 11:46
26

Simply I used array_filter function to achieve the solution as like follows

<?php

$input = array(
    'abc' => 0,
    'foo-bcd' => 1,
    'foo-def' => 1,
    'foo-xyz' => 0,
);

$filtered = array_filter($input, function ($key) {
    return strpos($key, 'foo-') === 0;
}, ARRAY_FILTER_USE_KEY);

print_r($filtered);

Output

Array
(
    [foo-bcd] => 1
    [foo-def] => 1
    [foo-xyz] => 0
)

For live check https://3v4l.org/lJCse

Suresh Velusamy
  • 2,338
  • 19
  • 24
  • 1
    Pay attention that this needs at least PHP 5.6.0 (due to the use of the constant ARRAY_FILTER_USE_KEY). In prior versions you can use: [code] – Netsurfer Dec 01 '17 at 08:41
20

From PHP 5.3 you can use the preg_filter function: here

$unprefixed_keys = preg_filter('/^foo-(.*)/', '$1', array_keys( $arr ));

// Result:
// $unprefixed_keys === array('bcd','def','xyz')
biziclop
  • 14,466
  • 3
  • 49
  • 65
19
$arr_main_array = array('foo-test' => 123, 'other-test' => 456, 'foo-result' => 789);

foreach($arr_main_array as $key => $value){
    $exp_key = explode('-', $key);
    if($exp_key[0] == 'foo'){
         $arr_result[] = $value;
    }
}

if(isset($arr_result)){
    print_r($arr_result);
}
Developer-Sid
  • 1,372
  • 11
  • 9
  • 20
    Before you take this solution, the one below is better. Never use array functions where simple string function will suffice. String functions are WAY faster. This will 'lag' with large arrays. – Martijn Nov 14 '14 at 10:36
  • 3
    I don't see the point of exploding the array keys into arrays. They are strings and the original question is just asking about a string prefix. Also OP is asking for "the elements" rather than just the values, so the numerically-indexed result is going to be useless - the keys are clearly important here, with the values being (presumably) anonymous 1/0 flags. – Jason Sep 09 '15 at 11:31
14
foreach($arr as $key => $value)
{
   if(preg_match('/^foo-/', $key))
   {
        // You can access $value or create a new array based off these values
   }
}
  • 4
    A regex is not really necessary in this case. The substr method is slightly more efficient – jfoucher Feb 12 '11 at 17:27
  • 2
    @jfoucher: That's true, however, personally, it's easier to read. –  Feb 12 '11 at 17:29
  • 3
    It may be more flexible, but comes at the cost of needing to escape special preg characters if you *don't* want to do a regular expression match. So use with caution. I would suggest you use REs only if you need REs. – Jason Sep 09 '15 at 11:49
8

Modification to erisco's Functional approach,

array_filter($signatureData[0]["foo-"], function($k) {
    return strpos($k, 'foo-abc') === 0;
}, ARRAY_FILTER_USE_KEY);

this worked for me.

Keyur
  • 1,113
  • 1
  • 23
  • 42
3

In addition to @Suresh Velusamy's answer above (which needs at least PHP 5.6.0) you can use the following if you are on a prior version of PHP:

<?php

$input = array(
    'abc' => 0,
    'foo-bcd' => 1,
    'foo-def' => 1,
    'foo-xyz' => 0,
);

$filtered = array_filter(array_keys($input), function($key) {
    return strpos($key, 'foo-') === 0;
});

print_r($filtered);

/* Output:
Array
(
    [1] => foo-bcd
    [2] => foo-def
    [3] => foo-xyz
)
// the numerical array keys are the position in the original array!
*/

// if you want your array newly numbered just add:
$filtered = array_values($filtered);

print_r($filtered);

/* Output:
Array
(
    [0] => foo-bcd
    [1] => foo-def
    [2] => foo-xyz
)
*/
Netsurfer
  • 5,543
  • 2
  • 29
  • 34
  • 1
    Please note (or at least for me) that this only returns the array key's that match. The answer below by @suresh-velusamy extracts the actual array with the original `$key => $value` pair. It is stated in the output of this answer, but was not yet mentioned explicitly – Martie Mar 29 '18 at 09:01
2

From PHP5.6, the array keys can be the sole subject of the filtration by using the ARRAY_FILTER_USE_KEY constant/flag.

From PHP7.4, arrow functions make custom functions more concise and allow values to be passed into the custom function's scope without use().

From PHP8, str_starts_with() can take the place of strpos(...) === 0

Code: (Demo)

$array = [
  'abc' => 0,
  'foo-bcd' => 1,
  'foo-def' => 1,
  'foo-xyz' => 0,
];

$prefix = 'foo';

var_export(
    array_filter(
        $array,
        fn($key) => str_starts_with($key, $prefix),
        ARRAY_FILTER_USE_KEY
    )
);

Output:

array (
  'foo-bcd' => 1,
  'foo-def' => 1,
  'foo-xyz' => 0,
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
1

You might pass a key-value single dimensional array and a specific prefix string 'foo-' to the function just made: filter_array_key_with_prefix

<?php

function filter_array_key_with_prefix($arr, $prefix) {
  return array_filter($arr, function($k) use ($prefix) {
    return strpos($k, $prefix) === 0;
  }, ARRAY_FILTER_USE_KEY);
}

$arr = array(
  'abc' => 0,
  'foo-bcd' => 1,
  'foo-def' => 1,
  'foo-xyz' => 0,
  // ...
);

$filtered = filter_array_key_with_prefix($arr, 'foo-');

var_dump($filtered);

Output:

array(3) {
  ["foo-bcd"]=>
  int(1)
  ["foo-def"]=>
  int(1)
  ["foo-xyz"]=>
  int(0)
}
mondayrris
  • 539
  • 4
  • 13