0

**EDIT:

I am trying to display the number of keys in my arrays that start with a "P", "M" and "D". I think I should be using array_maps and have some luck with it but I am now stuck and tried looking through the manual, on here and w3schools with no luck.


I'm using version 5.6.36 of PHP with XAMPP on a local server. I've tried playing around with array_maps which I think is the right command to use, but I just cant get my head around how to use it properly. I've read the manual on it, looked on here, looked on youtube and W3Schools with no luck. Can anyone help please?

I have this array:

$tasks = array
(
    0 => 'P1',
    1 => 'M1',
    2 => 'D1',
    3 => 'P2',
    4 => 'D2'
);

I want it to display this:

Array
(
    [P] => 2
    [M] => 1
    [D] => 2
)

See how it returns the number of P's M's and D's nice and neatly?

From what I understand, the solution code should be something like this:

$array2 = array_map(function(???????){
    return ??????????;
}, $tasks);

$array2a = (array_count_values($array2));

echo "<pre>"; print_r($array2a); echo "</pre>";

Please help?!

  • Possible duplicate of [Illegal string offset Warning PHP](https://stackoverflow.com/questions/9869150/illegal-string-offset-warning-php) – Alon Eitan Apr 08 '19 at 16:48
  • 1
    Where did this even come from `['group']`??? – AbraCadaver Apr 08 '19 at 16:53
  • Yeah, good question, sorry. I used a snippet of code from an existing post (which wasnt quite relevant to my issue) to get an idea of how the function works and am now at a point where it works it it is there but doesnt if I remove it. Usually I can fit snippets to how I need to use it but this one has stumped me! – Paul Cullis Apr 08 '19 at 17:36
  • Please extract a [mcve]! Your question is actually considered off-topic without one. As a new user here, also take the [tour] and read [ask]. – Ulrich Eckhardt Apr 08 '19 at 18:06
  • Thank you @UlrichEckhardt, I have edited accordingly. I hope this makes better sense now! – Paul Cullis Apr 09 '19 at 07:47

3 Answers3

0

you can use array_map as following :

$tasks = array
(
  0 => 'P1',
  1 => 'M1',
  2 => 'D1',
  3 => 'P2',
  4 => 'D2'
);
$charsToCheck = array('P','M','D');

$result = array_map(function($v) use ($charsToCheck){
if(in_array(substr( $v, 0, 1),$charsToCheck))
    return substr( $v, 0, 1);
}, $tasks);
print_r(array_count_values($result));

Result:-

Array
(
 [P] => 2
 [M] => 1
 [D] => 2
) 
Rakesh Jakhar
  • 6,380
  • 2
  • 11
  • 20
  • Perfect! Thank you so much @Rakesh Jakhar!! – Paul Cullis Apr 09 '19 at 08:35
  • What if the original array is not full, for example: Array ( [0] => P [1] => M [2] => [3] => [4] => ) It still works, but I get "array_count_values(): Can only count STRING and INTEGER values!" I can enter a "-" into the blank fields on my database but then that messes up the rest of my code. Can an if statement be added in there to check if the keys are null or something like that? – Paul Cullis Apr 09 '19 at 09:43
  • @PaulCullis use array_filter() to remove empty elements – Rakesh Jakhar Apr 09 '19 at 09:44
  • You're a genius. Thank you! – Paul Cullis Apr 09 '19 at 09:47
0

The function array_map() creates one output element from every input element. Since you don't want that, it is the wrong tool. Probably the easiest way to achieve your goal is to use a simple loop. However, if things get more complicated, this may not scale well. For those cases, array_reduce() could come in handy:

$input = [
    0 => 'P1',
    1 => 'M1',
    2 => 'D1',
    3 => 'P2',
    4 => 'D2',
];

$frequency = array_reduce(
    $input,
    function ($carry, $item) {
        $initial = substr($item, 0, 1);
        if (array_key_exists($initial, $carry)) {
            $carry[$initial] += 1;
        }
        return $carry;
    },
    [
        'P' => 0,
        'M' => 0,
        'D' => 0,
    ]
);

echo json_encode($frequency, JSON_PRETTY_PRINT) . PHP_EOL;

The point of this is that it defines what to do with a single element ($item) and how to modify the resulting state ($carry) in a single function, keeping this part away from the iteration part. Since this avoids mutable state, this can also be seen as a functional (as in "functional programming") approach.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
-1

You cannot use array_map for that... You could use reduce I guess but here's a fast and easy way... Basically you create your new array and do the counting according to the first letter of your tasks array.

$list = new Array();
foreach($tasks as $task){
    if($list[$task{0}]){
        $list[$task{0}]++;
    }else{
        $list[$task{0}] = 1;
    }
}

The problem you'd get with array_map is that it would always produce a 1:1 ratio of your array, which is not what you want...

(sorry for the bad PHP if it is, been ages...)

EDIT:

Using your edited question, here's your possible usage:

$array2 = array_map(function($val){
    return $val{0};
}, $tasks);

The key to both answers is the $var{0} part, this extracts the character at index 0...

Salketer
  • 14,263
  • 2
  • 30
  • 58