Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
1 / 1 / 0
Регистрация: 18.01.2017
Сообщений: 207

Как создать сложный фильтр многомерного массива? чтобы фильтровать по нескольким условиям, выбирать больше и меньше

16.01.2025, 13:52. Показов 838. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
есть массив например
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
Array
(
    [p-001] => Array
        (
            [id] => p-001
            [name] => Тестовый товар 1
            [color] => Синий
            [product_id] => p-001
            [count] => 10
            [price] => 200
            [currency] => р.
        )
 
    [p-002] => Array
        (
            [id] => p-002
            [name] => Тестовый товар 2
            [color] => Синий
            [product_id] => p-002
            [count] => 5
            [price] => 345
            [currency] => р.
        )
 
    [p-003] => Array
        (
            [id] => p-003
            [name] => Тестовый товар 3
            [color] => Синий
            [product_id] => p-003
            [count] => 0
            [price] => 150
            [currency] => р.
        )
 
    [p-004] => Array
        (
            [id] => p-004
            [name] => Тестовый товар 4
            [color] => Красный
            [product_id] => p-004
            [count] => 2
            [price] => 10
            [currency] => р.
        )
 
    [p-005] => Array
        (
            [id] => p-005
            [name] => Тестовый товар 5
            [color] => Белый
            [product_id] => p-005
            [count] => 7
            [price] => 100
            [currency] => р.
        )
 
    [p-006] => Array
        (
            [id] => p-006
            [name] => Тестовый товар 6
            [color] => Фиолетовый
            [product_id] => p-006
            [count] => 5
            [price] => 
            [currency] => р.
        )
 
    [p-007] => Array
        (
            [id] => p-007
            [name] => Тестовый товар 7
            [color] => Прозрачный
            [product_id] => p-007
            [count] => 6
            [price] => 900
            [currency] => р.
        )
 
    [p-008] => Array
        (
            [id] => p-008
            [name] => Тестовый товар 8
            [color] => Оранжевый
        )
 
)
Как написать фильтр, например чтобы найти все товары у которых price больше 100 и меньше 200, и color = Красный?
то по любому количеству параметров, чтобы можно было указывать числовые элементы массива больше или меньше.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.01.2025, 13:52
Ответы с готовыми решениями:

Как создать фильтр по нескольким условиям в поле, где дублируются данные?
Очень прошу помощи - голова закипает... Есть база данных рейсов автомобилей. В основной таблице "рейсы" есть поля: код, дата...

Сложный анализ таблиц по нескольким условиям
Доброе время суток всем! Возникла проблема анализа огромного объема данных, выкаченных из другой системы. Суть в том, что нужно найти...

Фильтр по нескольким условиям
Добрый день. Я хочу выводить только те строки таблицы, которые соответствуют введенной информации в html форме. Столкнулась с проблемой:...

7
Эксперт PHP
 Аватар для liris
4352 / 997 / 148
Регистрация: 16.01.2023
Сообщений: 2,453
16.01.2025, 14:38
В идеале это условие лучше подставлять в запрос к БД (максимально быстро работает и памяти меньше израсходует).

Но если нужно именно на PHP - лучше для каждого сложного поиска писать отдельный метод/функцию.

Но если нужно просто сравнить в лоб, то можно примерно так (в моем примере массив возвращается, но если нужно именно фильтровать (изменять исходный массив), то передавайте массив по ссылке и делайте unset для ненужных элементов):

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class Products
{
    private array $products = [];
    public function __construct(array $products)
    {
        $this->products = $products;
    }
 
    /**
     * @param $searchIndex
     * @param $conditionType
     * @param $searchValue
     * @return array
     * @throws Exception
     */
    public function getProductsByCondition($searchIndex, $conditionType, $searchValue): array
    {
        $result = [];
 
        if (!$this->isAllowedCondition($conditionType)) {
            return $result;
        }
 
        foreach ($this->products as $key => $product) {
            if (!isset($product[$searchIndex])) {
                continue;
            }
 
            switch ($conditionType) {
                case '==':  if ($product[$searchIndex] == $searchValue)
                                $result[$key] = $product;
                                break;
                case '===': if ($product[$searchIndex] === $searchValue)
                                $result[$key] = $product;
                                break;
                case '>':   if ($product[$searchIndex] > $searchValue)
                                $result[$key] = $product;
                                break;
                case '<':   if ($product[$searchIndex] < $searchValue)
                                $result[$key] = $product;
                                break;
                case '<=':  if ($product[$searchIndex] <= $searchValue)
                                $result[$key] = $product;
                                break;
                case '>=':  if ($product[$searchIndex] >= $searchValue)
                                $result[$key] = $product;
                                break;
            }
        }
 
        return $result;
    }
 
    /**
     * @param $conditionType
     * @return bool
     */
    private function isAllowedCondition($conditionType): bool
    {
        $allowedConditionTypes = [
            '==', '===', '<', '>', '>=', '<=', '!='
        ];
 
        return in_array($conditionType, $allowedConditionTypes);
    }
}
Массив с вашими тестовыми данными:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
$productsData = [
    'p-001' => [
        'id' => 'p-001',
        'name' => 'Тестовый товар 1',
        'color' => 'Синий',
        'product_id' => 'p-001',
        'count' => 10,
        'price' => 200,
        'currency' => 'р.',
    ],
    'p-002' => [
        'id' => 'p-002',
        'name' => 'Тестовый товар 2',
        'color' => 'Синий',
        'product_id' => 'p-002',
        'count' => 5,
        'price' => 345,
        'currency' => 'р.',
    ],
    'p-003' => [
        'id' => 'p-003',
        'name' => 'Тестовый товар 3',
        'color' => 'Синий',
        'product_id' => 'p-003',
        'count' => 0,
        'price' => 10,
        'currency' => 'р.',
    ],
    'p-004' => [
        'id' => 'p-004',
        'name' => 'Тестовый товар 4',
        'color' => 'Красный',
        'product_id' => 'p-004',
        'count' => 2,
        'price' => 10,
        'currency' => 'р.',
    ],
    'p-005' => [
        'id' => 'p-005',
        'name' => 'Тестовый товар 5',
        'color' => 'Белый',
        'product_id' => 'p-005',
        'count' => 7,
        'price' => 100,
        'currency' => 'р.',
    ],
    'p-006' => [
        'id' => 'p-006',
        'name' => 'Тестовый товар 6',
        'color' => 'Фиолетовый',
        'product_id' => 'p-006',
        'count' => 5,
        'price' => null,
        'currency' => 'р.',
    ],
    'p-007' => [
        'id' => 'p-007',
        'name' => 'Тестовый товар 7',
        'color' => 'Прозрачный',
        'product_id' => 'p-007',
        'count' => 6,
        'price' => 900,
        'currency' => 'р.',
    ],
    'p-008' => [
        'id' => 'p-008',
        'name' => 'Тестовый товар 8',
        'color' => 'Оранжевый',
    ],
];
Пример использования:

PHP
1
2
3
4
$productsCollection = new Products($productsData);
 
$blueProducts = $productsCollection->getProductsByCondition('color', '==', 'Синий');
$priceOver300 = $productsCollection->getProductsByCondition('price', '>=', 300);
0
 Аватар для sad67man
2598 / 1502 / 689
Регистрация: 23.08.2015
Сообщений: 3,800
16.01.2025, 15:42
liris, Только я бы возвращал объект коллекции

Тогда проще применять 2 фильтра условия И
PHP
1
2
3
4
$filteredProducts = $productsCollection
    ->filter('price', '>', '100')
    ->filter('price', '<=', '200')
    ->all();
Это получается AND. А что если нам нужно сделать ИЛИ? Здесь может лучше делать через спецификации. тогда выносится логика в объект, который возвращает true / false

PHP
1
2
$condition = new Condition('price', '>', '100');
$condition->isSatisfiedBy($product); //bool
Тогда можно реализовать разные штуки как

PHP
1
2
3
4
5
6
7
8
9
10
$condition = new AndCondition(
    new Condition('price', '>', '100'),
    new Condition('price', '<', '200'),
    new OrCondition(
        new Condition('color', '=', 'blue'),
        new Condition('color', '=', 'red')
    )
);
 
$filtered = $productsCollection->filter($condition)->all();
0
Эксперт PHP
 Аватар для liris
4352 / 997 / 148
Регистрация: 16.01.2023
Сообщений: 2,453
16.01.2025, 15:51
Цитата Сообщение от sad67man Посмотреть сообщение
Только я бы возвращал объект коллекции
Тогда проще применять 2 фильтра условия И
У меня была идея, что можно весь набор условий передавать массивом. Например:

PHP
1
2
3
4
5
$conditions = [
    ['price', '>', 300],
    ['price', '<', 500],
    ['color', '==', 'Синий'],
];
Но не уверен, что ТСу нужны эти усложнения.
0
1 / 1 / 0
Регистрация: 18.01.2017
Сообщений: 207
17.01.2025, 01:31  [ТС]
мне нужно чтобы условия передавались вот так:
PHP
1
2
3
4
5
$conditions = [
    'price' => '>300',
    'price' => '<500',
   'color' => 'Синий'
];
Добавлено через 1 час 29 минут
Нет, вот так:
PHP
1
2
3
4
$conditions = [
    'price' => ['>300', '<500'],
    'color' => 'Синий'
];
0
Невнимательный
 Аватар для ft4l
2835 / 1260 / 357
Регистрация: 08.02.2013
Сообщений: 7,332
Записей в блоге: 2
17.01.2025, 05:54
Цитата Сообщение от 4234 Посмотреть сообщение
$conditions = [ 'price' => '>300', 'price' => '<500', 'color' => 'Синий' ];
Таких массивов, с повторяющимися ключами, в php не бывает ... много где не бывает.

или другим способом хранить, или этот знак, если он уникальный для ключа, лепить к ключу '>price', '<price'
или нумеровать 'price0', 'price1', ...
Но 'price' => ['>300', '<500'] само по себе нумерация+
0
Эксперт PHP
 Аватар для liris
4352 / 997 / 148
Регистрация: 16.01.2023
Сообщений: 2,453
17.01.2025, 10:02
Цитата Сообщение от 4234 Посмотреть сообщение
нужно чтобы условия передавались вот так
Тогда вам придется писать логику разбора строки, выделения из нее символа. Абсолютно лишняя и ненужная работа.
Но хозяин - барин. Пишите, если хочется.
0
 Аватар для sad67man
2598 / 1502 / 689
Регистрация: 23.08.2015
Сообщений: 3,800
17.01.2025, 12:13
Формат можно конвертировать из одного вида в другой. Тогда можно придумывать любые форматы, какие душе пожелаете.

PHP
1
$params = FilterHelper::fromQuery('price>100;price<150;color=Красный,Зеленый');
Ну давайте я свою версию уже накидаю, может кто потом доведет до ума)

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ProductsCollection
{
    private $items;
 
    public function __construct(array $items)
    {
        $this->items= $items;
    }
 
    public function filter(ICondition $condition): self
    {
        $clone = clone $this;
        $clone->items = array_filter($this->items, function($product) use ($condition) {
            return $condition->isSatisfiedBy($product);
        });
        return $clone;
    }
 
    public function all(): array
    {
        return $this->items;
    }
}
PHP
1
2
3
4
interface ICondition
{
    public function isSatisfiedBy(array $product): bool;
}
И какую-нибудь факторку

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
class ConditionFactory
{
    private function create($key, $value): ?ICondition
    {
        switch ($key) {
            case 'price_from': return new MoreCondition('price', $value);
            case 'price_to': return new LessCondition('price', $value);
            case 'color': return new EqualCondition('color', $value);
        }
 
        return null;
    }
}
Либо на каждое поле отдельный класс, тут как душа пожелает. Можно и какой-то общий, и на отдельные поля уникальные фильтры. тут получается достаточно гибко.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ConditionFactory
{
    private function create($key, $value): ?ICondition
    {
        switch ($key) {
            case 'price_from': return new PriceFromCond($value);
            case 'price_to': return new PriceToCond($value);
            case 'color': return new ColorCond($value);
            case 'name': return new NameCond($value);
        }
 
        return null;
    }
}
Пример какого-нибудь класса
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PriceFromCond implements ICondition
{
    private $value;
 
    public function __construct($value)
    {
        $this->value = $value;
    }
 
    public function isSatisfiedBy(array $product): bool
    {
        return $product['price'] >= $this->value;
    }
}
Так же если выберем 2 цвета, то вероятно нужно будет делать через OR

PHP
1
2
3
4
5
$params = [
    'price_from' => 100,
    'price_to' => 150,
    'color' => ['Зеленый', 'Красный'],
];
Тогда нам нужно одинаковые поля склеивать через OR, а разные через AND.. Т.е. должно получиться как выше писал
PHP
1
2
3
4
5
6
7
8
$condition = new AndCondition([
    new PriceFromCond(100),
    new PriceToCond(150),
    new OrCondition([
        new ColorCond('Зеленый'),
        new ColorCond('Красный'),
    ]),
]);
Что-то типа такого.. каждую группу склеиваем через ORCondition

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class ConditionFactory
{
    public function createAll($params): ICondition
    {
        $condGroups = [];
 
        foreach ($params as $key => $values) {
            if (!is_array($values)) {
                $values = [$values];
            }
 
            foreach ($values as $value) {
                if ($cond = $this->create($key, $value)) {
                    $condGroups[$key][] = $cond;
                }
            }
        }
 
        $result = [];
 
        foreach ($condGroups as $group) {
            $result[] = new OrCondition($group);
        }
 
        return new AndCondition($result);
    }
 
    private function create($key, $value): ?ICondition
    {
        switch ($key) {
            //...
        }
 
        return null;
    }
}
Реализуем сами And и OrCondition

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class AndCondition implements ICondition
{
    private $conditions;
 
    /**
     * @param ICondition[] $conditions
     */
    public function __construct(array $conditions)
    {
        $this->conditions = $conditions;
    }
 
    public function isSatisfiedBy(array $product): bool
    {
        foreach ($this->conditions as $condition) {
            if (!$condition->isSatisfiedBy($product)) {
                return false;
            }
        }
        return true;
    }
}
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class OrCondition implements ICondition
{
    private $conditions;
 
    /**
     * @param ICondition[] $conditions
     */
    public function __construct(array $conditions)
    {
        $this->conditions = $conditions;
    }
 
    public function isSatisfiedBy(array $product): bool
    {
        foreach ($this->conditions as $condition) {
            if ($condition->isSatisfiedBy($product)) {
                return true;
            }
        }
        return false;
    }
}
Итого получается
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$products = new ProductsCollection([
    [
        'id' => 1,
        'price' => 100,
        'color' => 'Синий',
    ],
    [
        'id' => 2,
        'price' => 200,
        'color' => 'Зеленый',
    ],
    [
        'id' => 3,
        'price' => 300,
        'color' => 'Зеленый',
    ],
    [
        'id' => 4,
        'price' => 200,
        'color' => 'Красный',
    ],
]);
 
$conditionFactory = new ConditionFactory();
 
$condition = $conditionFactory->createAll([
    'price_from' => 100,
    'price_to' => 250,
    'color' => ['Зеленый', 'Красный'],
]);
 
$filtered = $products->filter($condition)->all();
 
var_dump($filtered); die();
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
17.01.2025, 12:13
Помогаю со студенческими работами здесь

Icollectionview Фильтр по нескольким условиям
Всем привет!Народ, подскажите вот какой момент. Есть у меня коллекция, которая содержит экземпляры класса. Таблица из бд, откуда я...

Фильтр в Datagridview по нескольким условиям
private void textBox2_TextChanged(object sender, EventArgs e) { if (WHGridView.DataSource ==...

Pandas - сортировака и фильтр по нескольким условиям
Приветствую! Помогите с решением: Есть dataframe, задача отсортировать строки по возрастанию по значениям трёх столбцов (А, В, С)...

DataGridView - поиск, фильтр и сортировка по нескольким условиям
Добрый день, при написании программы столкнулся с некоторой задачей. Как осуществить поиск, фильтрацию и сортировку по нескольким условиям...

Расширенный фильтр . Поиск значений по нескольким условиям
С помошью расширеннего фильтра найти расходы за март, апрель, май, июнь или июль 1997г. по накладным расходам и материалам сумма которых...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru