#php #arrays #multidimensional-array #array-intersect
#php #массивы #многомерный массив #массив-пересечение
Вопрос:
Я пытаюсь отфильтровать 2d-массивы, которые удовлетворяют двум условиям. Но это работает не так, как ожидалось. Я выяснил, что ошибка находится в array_intersect()
функции. Почему array_intersect()
здесь не работает корректно.Есть ли другой способ сделать это без итерации?
<?php
error_reporting(0);
$students = [
["name"=> 'k. l.james', "grade"=>8],
["name"=> 'k. l.james', "grade"=>9],
["name"=> 'e. musk', "grade"=>8],
["name"=> 'jone', "grade"=>9],
];
function filterByGrade($grade){
global $students ;
if (empty($grade)){
return $students ;
}else{
return array_filter($students , function($record) use($grade){
return ($record['grade'] == $grade);
});
}
}
function filterByName($name){
global $students;
if (empty($name)){
return $students;
}else{
return array_filter($students, function($record) use($name){
return (strcasecmp(str_replace(' ','',$record['name']),str_replace(' ','',$name)) == 0);
});
}
}
print_r(filterByGrade(8));
echo "<br/>";
print_r(filterByName('k.l.james'));
echo '<br/>';
print_r(array_intersect(filterByGrade(8), filterByName('k.l.james')));
?>
результаты таковы;
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [2] => Array ( [name] => e. musk [grade] => 8 ) )
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [1] => Array ( [name] => k. l.james [grade] => 9 ) )
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [2] => Array ( [name] => e. musk [grade] => 8 ) )
Я ожидаю, что последняя строка результата будет выглядеть следующим образом,
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ))
Если я поменял местами два массива в array_intersect() следующим образом, результаты будут разными.
print_r(array_intersect(filterByName('k.l.james'),filterByGrade(8)));
Затем я получаю следующий результат.
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [2] => Array ( [name] => e. musk [grade] => 8 ) )
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [1] => Array ( [name] => k. l.james [grade] => 9 ) )
Array ( [0] => Array ( [name] => k. l.james [grade] => 8 ) [1] => Array ( [name] => k. l.james [grade] => 9 ) )
Я заметил, что печатается только первый отфильтрованный массив array_intersect()
, несмотря на то, что учитывается пересечение двух массивов.
Комментарии:
1. Примечание: Строка «k.l.james» определяется как «k.l.james» в начальном массиве.
Ответ №1:
Вы можете создать функцию для фильтрации учащихся с использованием нескольких условий, вместо того, чтобы пытаться объединить 2 результата.
Функция :
/**
* Here, $condition array of keys/values used to filter $data.
* ex: ['name' => 'jone', 'grade' => 9]
*/
function filterArray($data, $conditions)
{
if (empty($conditions)) {
return $data;
}
return array_filter($data, function($record) use ($conditions) {
// Check all given conditions
foreach ($conditions as $key => $value) {
// If doesn't match, return false (don't keep in filtered array)
if ($record[$key] != $value) return false;
}
// conditions passed, add to array
return true;
});
}
Использование :
$students = [
["name"=> 'k. l.james', "grade" => 8],
["name"=> 'k. l.james', "grade" => 9],
["name"=> 'e. musk', "grade" => 8],
["name"=> 'jone', "grade" => 9],
];
print_r(filterArray($students, ['grade' => 8]));
// out : [["name"=> 'k. l.james', "grade" => 8],["name"=> 'e. musk', "grade" => 8]]
print_r(filterArray($students, ['name' => 'k. l.james']));
// out : [["name"=> 'k. l.james', "grade" => 8], ["name"=> 'k. l.james', "grade" => 9]]
print_r(filterStudents($students, ['grade' => 8, 'name' => 'k. l.james']));
// out : [["name"=> 'k. l.james', "grade" => 8]]
Дополнительные примечания :
global
в приведенном ниже коде использование не рекомендуется,$students
задается параметром функции.- Нет необходимости использовать
else
оператор после шаблона «возврат раньше» (if ($someCondition) { return; } else { }
).
Комментарии:
1. можете ли вы прокомментировать метод ниже
Ответ №2:
array_intersect()
работает корректно, если внутренние объекты массива сериализованы. Итак, я получил правильные результаты с помощью
print_r(
array_map('unserialize',
array_intersect(
array_map('serialize', filterByName('k.l.james')),
array_map('serialize', filterByGrade(8))
)
)
);
Могу ли я узнать, что более эффективно для фильтра веб-сайта, ответ @Syscall или мой метод.
Комментарии:
1. Интересный ответ, но немного сложный IMO (array_map / serializing / unserializing), и его довольно сложно читать 🙂 Мой ответ позволяет выполнить только один цикл для массива students (используя array_filter). В любом случае, эффективность, вероятно, зависит от объема данных и использования.