Remove all elements from array that have a key that does not start with a certain string
Asked Answered
A

10

95

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-?

Asturias answered 12/2, 2011 at 16:46 Comment(2)
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.Bypass
See also: #13767398Consumption
P
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.

Pulp answered 30/11, 2016 at 7:15 Comment(3)
Any difference in performance or usefulness compared to array_filter_key version provided by @erisco?Venture
Nope. There should not any difference in performance I guess. @MaciekSemikPulp
This is a core PHP function so it should be preferred.Gnathous
G
153

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();
}
Guillemot answered 12/2, 2011 at 16:58 Comment(4)
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.Miyamoto
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.Eyelet
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.Spyglass
With php8 you can also use str_starts_with($key, 'foo-')Caplan
A
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...
    }
}
Armhole answered 12/2, 2011 at 16:56 Comment(2)
You also can use: foreach ($array as $key => $value) { if (0 === strpos($key, 'foo-')) { ...use the $value... } }Also
The "4" here needs to be adjusted to whatever length "foo-" is.Miyamoto
B
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

Bluegreen answered 25/9, 2017 at 10:56 Comment(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]Tearoom
C
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')
Choreodrama answered 30/10, 2013 at 20:58 Comment(0)
G
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);
}
Giff answered 5/12, 2012 at 17:39 Comment(2)
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.Rebut
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.Miyamoto
P
14
foreach($arr as $key => $value)
{
   if(preg_match('/^foo-/', $key))
   {
        // You can access $value or create a new array based off these values
   }
}
Paradrop answered 12/2, 2011 at 16:55 Comment(3)
A regex is not really necessary in this case. The substr method is slightly more efficientHooghly
@jfoucher: That's true, however, personally, it's easier to read.Paradrop
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.Miyamoto
P
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.

Pulp answered 30/11, 2016 at 7:15 Comment(3)
Any difference in performance or usefulness compared to array_filter_key version provided by @erisco?Venture
Nope. There should not any difference in performance I guess. @MaciekSemikPulp
This is a core PHP function so it should be preferred.Gnathous
T
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
)
*/
Tearoom answered 1/12, 2017 at 9:2 Comment(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 explicitlyResidentiary
S
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,
)
Spyglass answered 27/11, 2020 at 12:50 Comment(0)
E
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)
}
Entwistle answered 2/4, 2022 at 17:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.