5

I need to get the stock values out of this array:

Array ( 
[stock0] => 1
[stockdate0] => 
[stock1] => 3 
[stockdate1] => apple 
[stock2] => 2 [
stockdate2] => 
) 

I need to pattern match on this array, where the array key = "stock" + 1 wildcard character. I have tried using the array filter function to get every other value on the PHP manual but the empty values seem to throw it out. I tried alot of different things I found but nothing is working.

Can this be done?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Oliver
  • 55
  • 1
  • 1
  • 3
  • Can we see the function you are passing array_filter? – Jeff Ober Oct 20 '09 at 16:17
  • What exactly do you try to achieve? – Gumbo Oct 20 '09 at 16:18
  • @ Jeff Ober function even($var) { return(!($var & 1)); } print_r(array_filter($stock, "even")); @ Gumbo I'm proccessing a form to pass the variables to a database. This part is for setting stock control on color variations. It is stored like this: red|blue|Green 1|2|3 ||Feb 2010 The second line runs 3 if statements that display the appropiate message (which if it is number 3 will incorperate the date) So that when this is displayed browser side I can simply get the arrays by exploding the delimiters. – Oliver Oct 21 '09 at 07:45

7 Answers7

4
<?php

$foo = 
array ( 
'stock0' => 1,
'stockdate0' => 1,
'stock1' => 3,
'stockdate1' => 2,
);

$keys = array_keys( $foo );
foreach ( $keys as $key ) {
    if ( preg_match( '/stock.$/', $key ) ) {
    var_dump( $key );
    }
}

I'm hoping I interpreted correctly and you wanted 'stock', 1 wildcard character thats not a newline, then end of string.

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • 1
    This looks like the straight answer to the OP's question. I would apply http://www.refactoring.com/catalog/inlineTemp.html to this solution to get rid of the temp variable $keys. – Ewan Todd Oct 20 '09 at 16:34
  • 1
    I only left the temporary variable incase for whatever reason he wanted to use them again, and usually it's easier to grasp for newbies the more variables you make instead of making the expressions harder to grasp. – meder omuraliev Oct 20 '09 at 17:15
  • I'm a big fan of RegEx and this could certainly be done this way. – ChronoFish Oct 21 '09 at 14:58
4

You should store those as:

Array(
  [0] => Array(
    stock => 1,
    stockdate => ...
  ),
  [1] => Array(
    stock => 3,
    stockdate => apple
  ),
  ...
)
Jeff Ober
  • 4,967
  • 20
  • 15
4

Since PHP 5.6.0 the flag option has been added to array_filter. This allows you to filter based on the array keys rather than its values:

array_filter($items, function ($key) {
  return preg_match('/^stock\d$/', $key);
}, ARRAY_FILTER_USE_KEY);
Peleg
  • 1,204
  • 10
  • 8
2

array_filter does not have access to the key and therefore is not the right tool for your job.

I belive what you're looking to do is this:

$stocks = Array ( 
"stock0" => 1,
"stockdate0" => '',
"stock1" => 3, 
"stockdate1" => 'apple',
"stock2" => 2,
"stockdate2" => ''
);


$stockList = array();  //Your list of "stocks" indexed by the number found at the end of "stock"

foreach ($stocks as $stockKey => $stock)
{
  sscanf($stockKey,"stock%d", &stockId);  // scan into a formatted string and return values passed by reference
  if ($stockId !== false)
     $stockList[$stockId] = $stock;
}

Now $stockList looks like this:

Array ( 
[0] => 1
[1] => 3 
[2] => 2 
)

You may need to fuss with it a bit, but I think this is what you are asking for.

HOWEVER, you really should be following Jeff Ober's advice if you have the option to do so.

ChronoFish
  • 3,589
  • 5
  • 27
  • 38
  • This looks good.
    At the moment however it's returning
    [0] => ''
    [1] => apple
    [2] => ''

    I.E the stockdate instead of the stock value
    I think I can adjust it - just feel free to help me with that as well!
    – Oliver Oct 21 '09 at 08:11
  • I just tried switching "stock%d" (wrong values) to "stockdate%d" which gave me the values: [] => 1 [0] => 2 [1] => 3 [2] => ''. Do you know how straighten the keys out? – Oliver Oct 21 '09 at 08:31
  • How in the world was this untested snippet accepted?!? `&stockId` really? Where is the dollar sign? Why are you passing by reference? Super wrong answer. https://3v4l.org/clG7b – mickmackusa Jun 28 '22 at 04:02
1
# returns array('stock1' => 'foo')
array_flip(preg_grep('#^stock.$#', array_flip(array('stock1' => 'foo', 'stockdate' => 'bar'))))

Not sure how good the performance is due to the regex and two flips, but excellent maintainability (no bug hunting in loops).

cmc
  • 4,294
  • 2
  • 35
  • 34
  • You will definitely need to go bug hunting if two or more elements have the same value OR if the value being flipped will be mutated when PHP uses it as a key (floats, nulls) ...not to mention the fact that you won't be able to flip non-scalar values. – mickmackusa Jun 28 '22 at 03:54
0

Ok working solution: Green for ChronoFish!

 $stockList = array();  //Your list of "stocks" indexed by the number found at the end of "stock"

foreach ($stock as $stockKey => $stock)
{
  sscanf($stockKey,"message%d", $stockId);  // scan into a formatted string and return values passed by reference
  if ($stockId !== false) {
     $stockList[$stockId] = $stock;
}

$stockList=array_values($stockList); //straightens array keys out
$stockList = array_slice ($stockList, "0", $count); //gets rid of blank value generated at end of array (where $count = the array's orginal length)
print_r ($stockList);
Oliver
  • 55
  • 1
  • 1
  • 3
0

To allow numeric suffixes that exceed 9, you can use rtrim() instead of regex to remove the numeric suffix, then check for an identical match again the search string.

Code: (Demo)

$stocks = [
    "stock0" => 1,
    "stockdate0" => '',
    "stock1" => 3, 
    "stockdate1" => 'apple',
    "stock4DON'TMATCHTHIS!!!" => 4,
    "stock2" => 2,
    "stockdate2" => '',
    "stock33" => 333,
    "stockdate33" => ''
];

$find = 'stock';
var_export(
    array_filter($stocks, fn($k) => rtrim($k, '0..9') === $find, ARRAY_FILTER_USE_KEY)
);

Output:

array (
  'stock0' => 1,
  'stock1' => 3,
  'stock2' => 2,
  'stock33' => 333,
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136