Question

How can I prevent duplicating the same block of code for each value that I want to search for?

I want to create a new array ($result) by counting for specific values within another multi-dimensional array ($data).

    $result = array();

    $result['Insulin'] = count(array_filter($data,function ($entry) {
                                            return ($entry['choice'] == 'Insulin'); 
                                        }
                                    )
                                );

    $result['TZD'] = count(array_filter($data,function ($entry) {
                                            return ($entry['choice'] == 'TZD'); 
                                        }
                                    )
                                );

    $result['SGLT-2'] = count(array_filter($data,function ($entry) {
                                            return ($entry['choice'] == 'SGLT-2'); 
                                        }
                                    )
                                );

$data array example:

array(2) {
  [0]=>
  array(9) {
    ["breakout_id"]=>
    string(1) "1"
    ["case_id"]=>
    string(1) "1"
    ["stage_id"]=>
    string(1) "1"
    ["chart_id"]=>
    string(1) "1"
    ["user_id"]=>
    string(2) "10"
    ["region"]=>
    string(6) "Sweden"
    ["choice"]=>
    string(7) "Insulin"
    ["switched_choice"]=>
    NULL
    ["keep"]=>
    string(1) "1"
  }
  [1]=>
  array(9) {
    ["breakout_id"]=>
    string(1) "1"
    ["case_id"]=>
    string(1) "1"
    ["stage_id"]=>
    string(1) "1"
    ["chart_id"]=>
    string(1) "1"
    ["user_id"]=>
    string(1) "7"
    ["region"]=>
    string(6) "Sweden"
    ["choice"]=>
    string(7) "Insulin"
    ["switched_choice"]=>
    NULL
    ["keep"]=>
    string(1) "1"
  }
}
Était-ce utile?

La solution

You may convert your anonymous function into a closure with the use keyword. Pass in a string variable for the value you want to match.

// Array of strings to match and use as output keys
$keys = array('Insulin','TZD','SGLT-2');
// Output array
$result = array();

// Loop over array of keys and call the count(array_filter()) 
// returning the result to $result[$key]
foreach ($keys as $key) {
  // Pass $key to the closure
  $result[$key] = count(array_filter($data,function ($entry) use ($key) {
    return ($entry['choice'] == $key);
  }));
}

Converting your var_dump() to an array and running this against it, the output is:

Array
(
    [Insulin] => 2
    [TZD] => 0
    [SGLT-2] => 0
)

You can simplify it with array_count_values() as well:

$result2 = array_count_values(array_map(function($d) {
  return $d['choice'];
}, $data));

print_r($result2);

Array
(
    [Insulin] => 2
)

If you need zero counts for the missing ones, you may use array_merge():

// Start with an array of zeroed values
$desired = array('Insulin'=>0, 'TZD'=>0, 'SGLT-2'=>0);
// Merge it with the results from above
print_r(array_merge($desired, $result2));
Array
(
    [Insulin] => 2
    [TZD] => 0
    [SGLT-2] => 0
)

Autres conseils

Not the most efficient algorithm in terms of memory, but you can map each choice onto a new array and then use array_count_values():

$result = array_count_values(array_map(function($item) {
  return $item['choice'];
}, $data));

Since 5.5 you can simplify it a little more by using array_column():

$result = array_count_values(array_column($data, 'choice'));

You can simplify your code easily if counting is your only goal :

$result = array();

foreach ($data AS $row) {
  if (!isset($result[$row['choice']])) {
    $result[$row['choice']] = 1;
  } else {
    $result[$row['choice']]++;
  }
}

If you want to count only specific choices, you can change the above code into something like this :

$result = array();
$keys = array('Insulin', 'TZD', 'SGLT-2');

foreach ($data AS $row) {
  if (!in_array($row['choice'], $keys)) {
    continue;
  }

  if (!isset($result[$row['choice']])) {
    $result[$row['choice']] = 1;
  } else {
    $result[$row['choice']]++;
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top