Retain elements in array if associative key starts with specific substring [duplicate]
Asked Answered
G

7

13

If I have array like:

array [
       y => 35
       x => 51
       z => 35
       c_3 => 4
       c_1 => 54
       c_6 => 53
       c_9 => 52
] 

I want to get array of:

array [c_3=>4, c_1=>54, c_6=>53, c_9=>52]

How can I filter out the elements which do not have keys starting with c_?

Ganger answered 13/8, 2012 at 11:25 Comment(1)
PHP8 offers a more semantic/inuitive native function to filter with and avoids the need for a regular expression. Shown in my answer on duplicate page: https://mcmap.net/q/81463/-remove-all-elements-from-array-that-have-a-key-that-does-not-start-with-a-certain-stringGarwin
J
11

Try this :

$filtred = array();

foreach($yourArray as $key => $value)
  if(preg_match('/c_\d/',$key))
    $filtred[] = $value;

print_r($filtred);
Jaquelynjaquenetta answered 13/8, 2012 at 11:28 Comment(1)
This answer filters by the keys and destroys the keys in the result array -- probably not the desired result.Garwin
B
7

Try This

 //your array
    $arr1 = array (
           "y" => 35,
           "x" => 51,
           "z" => 35,
           "c_3" => 4,
           "c_1" => 54,
           "c_6" => 53,
           "c_9" => 52
    );
// Array with keys you want
    $arr2 =  array (
           "c_3" => '',
           "c_1" => '',
           "c_6" => '',
           "c_9" => ''
    );
//use array_intersect_key to find the common  ;)
    print_r(array_intersect_key($arr1,$arr2));
Baggywrinkle answered 13/8, 2012 at 11:59 Comment(2)
Nice, didn't knew that command. For who wants more info about array_intersect_key: php.net/manual/en/function.array-intersect-key.phpVitrescent
This unexplained snippet only works if all of the desired keys are known in advance.Garwin
B
6

Check this solution with array_filter()

 $arr = [
   'y' => 35,
   'x' => 51,
   'z' => 35,
   'c_3' => 4,
   'c_1' => 54,
   'c_6' => 53,
   'c_9' => 52,
 ];

 $filtered = array_filter($arr, function($v) use($arr){
   return preg_match('#c_\d#', array_search($v, $arr));
 });

Solution below will work in PHP >= 5.6.0

 $filtered = array_filter($arr, function($k){
   return preg_match('#c_\d#', $k);
 }, ARRAY_FILTER_USE_KEY);

Both solutions work I've checked them.

Bernardabernardi answered 13/8, 2015 at 13:31 Comment(1)
preg_match('#c_\d#', array_search($v, $arr)) is a bad idea. Watch it fail: demo The reason is because array_search() returns the key of the first matching value. This should not be used in any script for any reason.Garwin
T
2

You can try using array_filter().

There are some interesting examples on the php documentation page. One of them covers filtering array keys.

Twister answered 13/8, 2012 at 11:29 Comment(1)
This vague hint does not go very far to solve this problem. This answer would have been better as a comment under the question.Garwin
B
2

I have tried the above solution but none of the solutions above worked for me in PHP 5.6

So, I tried and used different solution which worked for me...

$subArray = array();

foreach($arryDetails as $key => $value)
  if(preg_match('/^c_/',$key))
    $subArray[$key] = $value;

print_r($subArray);
Benjamin answered 27/2, 2019 at 7:1 Comment(1)
subArray is a misleading variable array. Rather than creating a new array, it may be desirable to simply mutate the original array by making unset() calls.Garwin
G
0

Use array_slice: http://php.net/manual/en/function.array-slice.php if you want just select known keys. Here you have solution for filtering arrays by keys: PHP: How to use array_filter() to filter array keys?

Gordon answered 13/8, 2012 at 11:28 Comment(1)
array_slice() is of absolutely no benefit for this task. The linked page is also not relevant -- it demonstrates whole key filtering where as this question is filtering on partial key matches.Garwin
I
0

I actually had similar question and lookout for the answers here, but nothing really matched my expectations.

I wanted something more reusable which I could use throughout all my projects, so I ended up writing this function:

   /**
* Create a new a array containing only the key with a certain $pattern or $subString.
*
* Note: You cannot use both $subString and $pattern at once ($substring has precedence on $pattern).
*
* @param $errorMessage String to return the error message.
* @param $source Array in which we must extract data.
* @param $subString String/Int/Array substring (or array of substring) to seek in the key name.
* @param $pattern String regex for validating the key.
* @param $useValueAsKey Boolean if true it will use the value as the key in the new array (scalar values only).
*/
public static function extractSubArray(&$errorMessage, array &$source, $subString ="", $pattern = "", $useValueAsKey=false){
    
    $newArray = array();
    
    $errorMessage = "";
    
    $dbManager = GeneralDbManager::getInstance();
    
    if (empty($source)){
        
        $errorMessage = $dbManager->getErrorMessage("SOURCE_ARRAY_IS_EMPTY_ERR", "The array supplied is empty.");
    }
    elseif(empty($subString) and empty($pattern)){
        
        $errorMessage = $dbManager->getErrorMessage("NO_SUBSTR_OR_PATTERN_ERR", "There are no substring or pattern to match the keys in the array.");
    }
    elseif (!empty($subString) and !(is_string($subString) or is_numeric($subString) or is_array($subString))){
        
        $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_SUBSTRING_ERR", "The substring you supplied to match the keys is invalid.");
    }
    elseif(!empty($pattern) and !RegularExpression::testRegex($pattern)){
        
        $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_PATTERN_ERR", "The regular expression you supplied to match the keys is invalid.");
    }
    else{

        foreach ($source as $key => $value){
            
            if (self::isKeyMatchSubstring($key, $subString, $pattern)){
                
                if ($useValueAsKey and (is_string($value) or is_numeric($value))){
                    
                    $newArray[$value] = $value;     
                }
                else{
                    
                    $newArray[$key] = $value;
                }
            }       
        }
        
        if (empty($newArray)){
            
            $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_PATTERN_ERR", "We were not able to match any keys in the array with the substring or the regular expression.");
        }
    }
    
    unset($dbManager);
    
    return $newArray;
}

/**
* Validate that the $key contains the $substring (string or array) or match the $pattern.
*
* @param $key String to validate
* @param $subString String/Int/Array containing the subString to seek.
* @param $pattern String regex for validating the key.
*/
private static function isKeyMatchSubstring($key, $subString, $pattern){
    
    $matched = false;
    
    if (!empty($subString)){
        
        if (is_string($subString) or is_numeric($subString)){
            
            if(strpos(strtolower($key), strtolower($subString)) !== false){
                
                $matched = true;    
            }
        }
        else{ //array
            
            foreach($subString as $testString){
                
                $matched = self::isKeyMatchSubstring($key, $testString, "");
                    
                if ($matched){
                        
                    break;  
                }
            }
        }   
    }
    elseif(!empty($pattern)){
        
        $matched = preg_match($pattern, $key);
    }
    
    return $matched;
}

It uses a function named testRegex(), so I guess I can supply that code too:

/**
* Make sure that a regular expression works in PHP.
*
* @param $regex String the regular expression to validate.
*
* @return Boolean
*/
public static function testRegex($regex){
    
    $isValid = false;
    
    if (!empty($regex) and is_string($regex)){
        
        if (@preg_match($regex, null) !== false){
            $isValid = true;
        }
    }
    
    return $isValid;
}

And, of course, how good would be a function without unit tests?

    public function testExtractSubArray(){
    
    $errorMessage = "";
    
    $source = array();
    
    //no data
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    //no substring or pattern
    $source = array(1 => 1);
    
    
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //invalid substring
    $dbmanager = GeneralDbManager::getInstance();
    
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, $dbmanager, "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    unset($dbmanager);
    
    
    //invalid pattern
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "[]123", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //no match
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "pokemon", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //valid substring
    $source = array("woot1" => "homer", "woot2" => "bart", "woot3" => "lisa", "doh1" => "marge", "doh2" => "simpson");
    
    $newArray = Tool::extractSubArray($errorMessage, $source, "WOOT", "", false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertContains("homer", $newArray);
    
    $this->assertContains("bart", $newArray);
    
    $this->assertContains("lisa", $newArray);
    
    $this->assertNotContains("marge", $newArray);
    
    $this->assertNotContains("simpson", $newArray);
    
    
    //use value as key
    $newArray = Tool::extractSubArray($errorMessage, $source, "WOOT", "", true);
    
    
    $this->assertTrue(array_key_exists("homer", $newArray));
    
    $this->assertTrue(array_key_exists("bart", $newArray));
    
    $this->assertTrue(array_key_exists("lisa", $newArray));
    
    
    //substring array
    $source = array("stan_march" => "normal", "kyle_brofloski" => "jew", "eric_cartman" => "asshole", "kenny_mccormick" => "dead", "butters_stotch" => "pushover");
    
    $newArray = Tool::extractSubArray($errorMessage, $source, array("stan", "kyle", "cartman"), "", false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertContains("normal", $newArray);
    
    $this->assertContains("jew", $newArray);
    
    $this->assertContains("asshole", $newArray);
    
    $this->assertNotContains("dead", $newArray);
    
    $this->assertNotContains("pushover", $newArray);
    
    
    //regex
    $source = array("[email protected]" => 1, "jonathan" => 2, "12345" => 3, "more $$$" => 4, "$?%$?%$%?" => 5);
    
    $newArray = Tool::extractSubArray($errorMessage, $source, "", RegularExpression::ALPHA_NUMERIC, false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertNotContains(1, $newArray);
    
    $this->assertContains(2, $newArray);
    
    $this->assertContains(3, $newArray);
    
    $this->assertNotContains(4, $newArray);
    
    $this->assertNotContains(5, $newArray);
}

Additional note: This code uses getErrorMessage() method to fetch the translation of the error message in the database. Since those error messages are meant for debugging purpose, they can be hard coded directly in the code for increased performance (no need to instantiate the class for fetching the error message and to open a connection to the database).

Inn answered 12/8, 2015 at 19:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.