21

Possible Duplicate:
Pattern Match on a Array Key

I need to get all the elements in an array with a specific key pattern. For example in this array:

$items = array(
   "a"         => "1",
   "b"         => "2",
   "special_1" => "3",
   "c"         => "4",
   "special_2" => "5",
   "special_3" => "6",
   "d"         => "7"
);

I would need all elements with a key containing the string special_. These should define a new array:

$special_items = array(
   "special_1" => "3",
   "special_2" => "5",
   "special_3" => "6",
);

Is there a smart method besides a while loop?

Community
  • 1
  • 1
Steeven
  • 4,057
  • 8
  • 38
  • 68
  • duplicate of https://stackoverflow.com/questions/10583591/how-to-get-a-subset-of-post-array-with-keys-starting-with-a-prefix , my answer which provides a custom function named `preg_grep_keys()` may be useful to people interested in this question. – goat Aug 08 '18 at 02:22

5 Answers5

23

How about this?

$special_items = array();

foreach($items as $key => $val) {
    if(substr($key, 0, 8) == 'special_')
        $special_items[$key] = $val;
}
Austin Brunkhorst
  • 20,704
  • 6
  • 47
  • 61
7

First you need to get an array containing the keys. array_keys

Then, you need to filter the keys to find the ones you want. array_filter

Use this callback:

function($a) {return substr($a,0,8) == "special_";}

Then flip the array so that the keys are keys again instead of values. array_flip

Finally, intersect those keys with the original array. array_intersect_key

Result:

$special_items = array_intersect_key($items,array_flip(array_filter(array_keys($items),function($a) {return substr($a,0,8) == "special_";})));
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
5

You can use FilterIterator

$iterator = new SpecialFilter($items, 'special');
var_dump(iterator_to_array($iterator));


Output

array
  'special_1' => string '3' (length=1)
  'special_2' => string '5' (length=1)
  'special_3' => string '6' (length=1)

Class Used

class SpecialFilter extends FilterIterator {
    private $f;
    public function __construct(array $items, $filter) {
        $object = new ArrayObject( $items );
        $this->f = $filter;
        parent::__construct( $object->getIterator() );
    }
    public function accept() {
        return 0 === strpos( $this->getInnerIterator()->key(), $this->f );
    }
}
kaiser
  • 21,817
  • 17
  • 90
  • 110
Baba
  • 94,024
  • 28
  • 166
  • 217
  • 7
    Yes! OO tech is the winner. Why make the thing simple when we can complicate them? 2 new, one inheritance (at least) to do 3 lines of code: for/if/doit – Aubin Oct 14 '12 at 23:06
  • 1
    `Is there a smart method besides a while loop?` Yes If `for/if/doit` is sufficient they would be nothing like `Iterators` – Baba Oct 14 '12 at 23:09
  • Nice, clean, test-able... +1 – kaiser Dec 29 '13 at 14:38
  • @Aubin Right, because who would want an easy to use and extend utility class when they can just copy paste blocks of code everywhere? I genuinely feel for anyone inheriting your code. Genuinely this is the best answer to OP's question. – Hybrid web dev Sep 28 '22 at 04:08
1
$special_items = array_intersect_key(array_flip(preg_grep('/^special_\d+/', array_keys($items))), $items);

Please don't actually use that. Just use a foreach loop with strpos + an if statement like all normal people would.

goat
  • 31,486
  • 7
  • 73
  • 96
1

how about

$keys = preg_grep( "/special_/i", array_keys( $items ) );

$new_array = array();

foreach( $keys as $k )
{
    $new_array[ $k ] = $items[ $k ];
}
Aubin
  • 14,617
  • 9
  • 61
  • 84
Seth
  • 558
  • 3
  • 6