array_filter с ассоциативным массивом?

#php #multidimensional-array

#php #многомерный массив

Вопрос:

Я использую array_filter, чтобы сделать что-то вроде этого:

 function endswithy($value) {
    return (substr($value, -1) == 'y');
}

$people = array("Johnny", "Timmy", "Bobby", "Sam", "Tammy", "Danny", "Joe");
$withy = array_filter($people, "endswithy");
var_dump($withy);
  

НО с дополнительной опцией в filter, например

 $people = array(
             "Johnny"=>array("year"=>1989, "job"=>"prof"),
             "Timmy"=>array("year"=>1989,  "job"=>"std"),
             "Bobby"=>array("year"=>1988),
             "Sam"=>array("year"=>1983),
             "Tammy"=>array("year"=>1985),
             "Danny"=>array("year"=>1983),
             "Joe"=>array("year"=>1989,"job"=>"prof"));
  

или

 $people = array(
             array("name"=>"Johnny","year"=>1989, "job"=>"prof"),
             array("name"=>"Timmy","year"=>1989,  "job"=>"std"),
             array("name"=>"Bobby""year"=>1988),
             array("name"=>"Sam","year"=>1983),
             array("name"=>"Tammy","year"=>1985),
             array("name"="Danny","year"=>1983),
             array("name"="Joe","year"=>1989,"job"=>"prof"));
  

Как я могу получить только эти данные (заканчивающиеся на y и year=1989 и job=prof ), могу ли я использовать array_filter?
или какая-либо встроенная функция для этого?

 $people = array(
                 "Johnny"=>array("year"=>1989, "job"=>"prof")
  );
  

или

 $people = array(
                 array("name="Johnny","year"=>1989, "job"=>"prof")
  );
  

Комментарии:

1. Можете ли вы использовать name в качестве значения внутреннего массива, а не ключа внешнего массива? Т.е., $people = array(array('name' => 'Johnny', 'year' => 1989, 'job' => 'prof'), ...)

2. Если вы можете это сделать, тогда нет проблем с использованием array_filter() . Вы получите массив в качестве аргумента функции обратного вызова ( endswithy() ), так что вы можете проверить как имя, так и год. Если вам это нужно только один раз, вы также можете использовать foreach цикл для удаления ненужных элементов. Я привел примеры с обоими array_filter() и foreach в моем ответе ниже.

Ответ №1:

PHP 5.6 вводит необязательный флаг ARRAY_FILTER_USE_KEY , который позволит это:

 function endswithy($name) {
    return (substr($name, -1) == 'y');
}

$people = array(
     "Johnny"=>array("year"=>1989, "job"=>"prof"),
     "Timmy"=>array("year"=>1989,  "job"=>"std"),
     "Bobby"=>array("year"=>1988),
     "Sam"=>array("year"=>1983),
     "Tammy"=>array("year"=>1985),
     "Danny"=>array("year"=>1983),
     "Joe"=>array("year"=>1989,"job"=>"prof")
);

$peopleEndingInY = array_filter($people, 'endswithy', ARRAY_FILTER_USE_KEY);

// Outputs: 5
var_dump(count($peopleEndingInY));
  

Если вам нужно сохранить и ключ и значение, другой флаг ARRAY_FILTER_USE_BOTH сделает это, как показано в этом примере:

 $ar = array(
    'key1' => 'value1',
    'key2' => 'value2'
);

//Note that this doens't actually filter anything since it doesn't return a bool.
$output = array_filter($ar, function($value, $key){
    echo sprintf("%s => %sn", $key, $value);
}, ARRAY_FILTER_USE_BOTH);
  

Комментарии:

1. отличный ответ, который не требует от вас изменения структуры данных.

Ответ №2:

Либо используйте foreach со структурой вашего текущего массива:

 $people = array(
    "Johnny" => array("year" => 1989, "job" => "prof"),
    "Timmy"  => array("year" => 1989, "job" => "std"),
    "Bobby"  => array("year" => 1988),
    "Sam"    => array("year" => 1983),
    "Tammy"  => array("year" => 1985),
    "Danny"  => array("year" => 1983),
    "Joe"    => array("year" => 1989, "job" => "prof"),
);

foreach ( $people as $name => $info ) {
    if ( substr($name, -1) !== 'y' || $info['year'] != 1989 ) {
        unset($people[$name]);
    }
}

print_r($people);

// output:
Array
(
    [Johnny] => Array
        (
            [year] => 1989
            [job] => prof
        )
    [Timmy] => Array
        (
            [year] => 1989
            [job] => std
        )
)
  

Или преобразовать ваш массив так, чтобы name было значением внутреннего массива:

 $people = array(
    array('name' => 'Johnny', 'year' => 1989, 'job' => 'prof'),
    array('name' => 'Timmy' , 'year' => 1989, 'job' => 'std'),
    array('name' => 'Bobby' , 'year' => 1988),
    array('name' => 'Sam'   , 'year' => 1983),
    array('name' => 'Tammy' , 'year' => 1985),
    array('name' => 'Danny' , 'year' => 1983),
    array('name' => 'Joe'   , 'year' => 1989, 'job' => 'prof'),
);

function filter($item) {
    return substr($item['name'], -1) === 'y' amp;amp; $item['year'] == 1989;
}

$filteredPeople = array_filter($people, 'filter');

print_r($filteredPeople);

// output:
Array
(
    [0] => Array
        (
            [name] => Johnny
            [year] => 1989
            [job] => prof
        )
    [1] => Array
        (
            [name] => Timmy
            [year] => 1989
            [job] => std
        )
)
  

Комментарии:

1. во втором примере, почему нам нужно преобразовать массив $ people? это ограничение array_filter?

2. Нет, это не ограничение array_filter() . Если вам не нужен $people в исходном виде после фильтрации, вы можете смело присвоить результат $people , т.е. $people = array_filter($people, 'filter'); .

3. извините за двоичный файл . ваш код работает отлично, но я не понял,. что вы объясняете в своих комментариях здесь. можете ли вы привести больше примеров по этому поводу. большое спасибо.

4. Что вы имели в виду своим вопросом в первом комментарии (о преобразовании $people )? Речь шла о $filteredPeople = array_filter($people, 'filter'); строке? Если да, вы можете смело писать $people = array_filter($people, 'filter'); .