7

is it possible to do searching in PHP array same we do in MySQL.

Eg: I have this array

array(
  'mark@test.com'=> `Mark Mian`,
  'jhon@test.com'=> `John jack`,
  'logon@test.com'=> `Bob Logon`,
  'Stela@test.com'=> `Stela Josh`,
  'json@test.com'=> `Json Josh`
  'bobby@test.com'=> `Bob Mark`
)

and I would to do this type of searching,

Eg: If I search Mark it should return me this

'mark@test.com' => `Mark Mian

If I search Bob it should return me

'bobby@test.com'=> Bob Mark

'logon@test.com'=> Bob Logon,

If I search only a it should return me those elements which contains a eg:

'mark@test.com'=> Mark Mian,

'jhon@test.com'=> John jack,

'Stela@test.com'=> Stela Josh,

'bobby@test.com'=> Bob Mark

Note: Search should be by key or value

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Qazi
  • 5,015
  • 8
  • 42
  • 62

7 Answers7

7
$needle="bob";
$output=array();
foreach($array as $k=>$v)
{
   if(stristr($k,$needle) || stristr($v,$needle))
   $output[$k]=$v;
}
print_r($output);

Fiddle

That is if you want to search keys and values both, Remove the keys part if you just want to search values.

Hanky Panky
  • 46,730
  • 8
  • 72
  • 95
6

Here is a preg_grep solution that should work more like a WHERE REGEXP 'PATTERN' in MySQL. I modified Daniel Klein's preg_grep_keys function to search for the pattern within array keys, and added an array_merge to it, which should work with the arrays with non-numeric keys. If the keys are numeric, just use a mere preg_grep solution (preg_grep('~Mark~i', $arr); to find all array elements having mark or Mark, etc.).

array_merge
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array. If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.

function preg_grep_keys_values($pattern, $input, $flags = 0) {
    return array_merge(
      array_intersect_key($input, array_flip(preg_grep($pattern, array_keys($input), $flags))),
      preg_grep($pattern, $input, $flags)
   );
}

$a = array(
  'mark@test.by.com'=> "Mark Mian lv",
  'jhon@test.lv.com'=> "John jack lv",
  'logon@test.en.com'=> "Bob Logon",
  'Stela@test.es.com'=> "Stela Josh",
  'json@test.es.com'=> "Json Josh",
  'bobby@test.lv.com'=> "Bob Mark"
);

$r = preg_grep_keys_values('~lv~i', $a);
print_r($r);

See this IDEONE demo

The code above searches for lv (case-insensitively) in the keys first, then in the values, and then merges the results into 1 array. Thus, the results are:

[jhon@test.lv.com] => John jack lv
[bobby@test.lv.com] => Bob Mark
[mark@test.by.com] => Mark Mian lv
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
4

An easy approach would be to use array_filter

If you want regex's, this would work

$regex = '~test~';
$result = array_filter($data, function($item) use ($regex) {
    return preg_match($regex, $item);
});

Or just a simple contains search

$search = 'test';
$result = array_filter($data, function($item) use ($search) {
    return stristr($value, $search);
});

If you have to search for both - key and value, you could append the parameter ARRAY_FILTER_USE_BOTH to array_filter.

$search = 'test';
$result = array_filter($data, function($item, $key) use ($search) {
    return stristr($value, $search) || stristr($key, $search);
}, ARRAY_FILTER_USE_BOTH);

And finally, you could combine array_filter with preg_grep to search for both at once.

$search = '~bob~i';
$result = array_filter($data, function() use ($search) {
    return count(preg_grep($search, func_get_args()));
}, ARRAY_FILTER_USE_BOTH);
Philipp
  • 15,377
  • 4
  • 35
  • 52
  • 1
    Sorry one more. What about `'~bob~i';` :P. +1 regardless – Hanky Panky Mar 18 '16 at 10:19
  • @HankyPanky I added an preg_grep version which searched for both at the same time – Philipp Mar 18 '16 at 10:29
  • using `stristr` is a bad idea, because 1) you don't need to extract the substring, 2) if the needle parameter can be evaluated to false, you will get a wrong result, example: `if (stristr('abc0abc', '0')) echo 'toto';`. You should use `stripos` instead and testing if it with a strict comparaison: `return stripos(.....) !== false;` – Casimir et Hippolyte Mar 18 '16 at 12:18
2

You want to filter an array, use array_filter that is designed for.

If you only search literal strings, you don't need to use a regex:

$needle = 'bob';

$result = array_filter($data, function ($k, $v) use ($needle) {
    return stripos($k, $needle) !== false || stripos($v, $needle) !== false;
}, ARRAY_FILTER_USE_BOTH);

If you want to be able to filter with a regex:

$pattern = '~n.*e~i';

$result = array_filter($data, function ($k, $v) use ($pattern) {
    return !empty(preg_grep($pattern, [$k, $v]));
}, ARRAY_FILTER_USE_BOTH);
Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
0
   $search = "Mark"

  $array = array(
  'mark@test.com'=> `Mark Mian`,
 'jhon@test.com'=> `John jack`,
 'logon@test.com'=> `Bob Logon`,
 'Stela@test.com'=> `Stela Josh`,
 'json@test.com'=> `Json Josh`
'bobby@test.com'=> `Bob Mark`
 )
       foreach ($array as $key => $value) {
         if (stristr($value, $search) == '') {
        //not found
        }else{
      //found
       }

this is the best approach search for any substring , case-insensitive and fast

just like like in mysql

ex:

select * from table where name = "%Mark%"

Yahya Ayyoub
  • 322
  • 2
  • 10
0

From PHP8, str_contain() becomes the preferred native function to make case-insensitive searches without reduced syntax.

Searching for a lowercase b does a fine job of demonstrating the case-insensitive search on keys and values.

Code: (Demo)

$array = [
    'mark@test.by.com'=> "Mark Mian lv",
    'jhon@test.lv.com'=> "John jack lv",
    'logon@test.en.com'=> "Bob Logon",
    'Stela@test.es.com'=> "Stela Josh",
    'json@test.es.com'=> "Json Josh",
    'bobby@test.lv.com'=> "Bob Mark"
];

$needle = 'b';

var_export(
    array_filter(
        $array,
        fn($v, $k) => str_contains($v, $needle) || str_contains($k, $needle),
        ARRAY_FILTER_USE_BOTH
    )
);

Output:

array (
  'mark@test.by.com' => 'Mark Mian lv',
  'logon@test.en.com' => 'Bob Logon',
  'bobby@test.lv.com' => 'Bob Mark',
)

If you want to be cute and make a single function call inside of array_filter(), then you could just concatenate $v and $k together, but then you risk the arbitrarily nominated delimiting character(s) being matched. For stability, just make two calls per iteration.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0
$data_array = array_filter($data_array , function ($item) use ($your_string) {
            return strpos($item['array_key'], $your_string) !== false;
        });

This replace the array with matching string

Tara
  • 470
  • 4
  • 13