Как запрашивать пользователей и группировать их по возрастному диапазону, используя laravel eloquent

Я хочу запрашивать пользователей и группировать их по возрастному диапазону

Это то, что я сделал до сих пор

User::applicant()->get()
                ->groupBy(function ($item) {
                    return Carbon::parse($item->dob)->age;
                })
                ->map(function ($collection) {

                    return $collection->count();
                });

Это то, что я получил из запроса выше

Как запрашивать пользователей и группировать их по возрастному диапазону, используя laravel eloquent

Теперь хотите получить коллекцию и упорядочить по возрастному диапазону

18-24: 1,
25-35: 5,
36-45: 89,
46+ : 84

У вас есть определенные возрастные диапазоны, которые вы хотите?

thisiskelvin 15.05.2019 17:21

Есть ли также 0-18?

thisiskelvin 15.05.2019 17:24

Да, я отредактировал свой вопрос @thisiskelvin

Theodory Faustine 15.05.2019 17:24

Нет 0-18, потому что это сайт агентства по подбору персонала, мы не ожидаем, что соискатели моложе 18 лет.

Theodory Faustine 15.05.2019 17:25

Чтобы было ясно, это для подсчета людей в этих возрастных группах, а не для того, чтобы фактические люди были сгруппированы вместе?

thisiskelvin 15.05.2019 17:25

Да, мне нужно только количество людей в этих диапазонах для целей аналитики @thisiskelvin

Theodory Faustine 15.05.2019 17:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
2 382
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я собираюсь использовать комбинацию map() и mapToGroups(), я почти уверен, что должен быть более простой способ, но мне это понравилось:

$ranges = [ // the start of each age-range.
    '18-24' => 18,
    '25-35' => 25,
    '36-45' => 36,
    '46+' => 46
];

$output = User::applicant()
    ->get()
    ->map(function ($user) use ($ranges) {
        $age = Carbon::parse($user->dob)->age;
        foreach($ranges as $key => $breakpoint)
        {
            if ($breakpoint >= $age)
            {
                $user->range = $key;
                break;
            }
        }

        return $user;
    })
    ->mapToGroups(function ($user, $key) {
        return [$user->range => $user];
    })
    ->map(function ($group) {
        return count($group);
    })
    ->sortKeys();

dd($output);

Идея этого состоит в том, чтобы добавить к каждой записи атрибут со значением, соответствующим их возрастному диапазону, а затем сгруппировать их по этому ключу, создав набор массивов пользователей, сгруппированных по диапазону, чтобы, наконец, подсчитать элементы для каждого подмассива внутри этого ключа.

Это должно вернуть что-то вроде:

=> Illuminate\Support\Collection {#2948
     all: [
       "25-35" => 1,
       "36-45" => 2,
       "46+" => 1,
     ],
   }

Я хочу объединить их в диапазоне 25-46 => 5 @HCK.

Theodory Faustine 15.05.2019 17:55

@TheodoryFaustine, как вы можете видеть в начале моего поста, я указал набор контрольных точек по возрасту, если вы хотите диапазон 25-46, просто включите: [ ..., 25, 47, ... ] в массив $ranges.

Kenny Horna 15.05.2019 17:56

Кстати, забыл отсортировать ключи, исправил в ответ.

Kenny Horna 15.05.2019 17:58

@TheodoryFaustine Я обновил свой ответ, чтобы вернуть ожидаемый результат.

Kenny Horna 15.05.2019 18:16

@HCK Не знал о ->mapToGroups(). Приятно знать

thisiskelvin 15.05.2019 18:18

@thisiskelvin да, у класса Collection есть несколько действительно интересных методов. Вот почему такого рода вопросы привлекают мое внимание, это маленькие головоломки, которые нужно решить. У Адама Уотэма есть хороший курс (Рефакторинг в коллекции, если я не ошибаюсь), когда он использует эту библиотеку, не видел ее, но у нее отличные отзывы.

Kenny Horna 15.05.2019 18:20

@HCK Прочитай pdf! Очень хорошо, еще нужно пересмотреть несколько частей.

thisiskelvin 15.05.2019 18:21

@thisiskelvin не знал, что есть PDF. теперь точно посмотрю ;)

Kenny Horna 15.05.2019 18:22

@HCK добавил вас в твиттер, кстати

thisiskelvin 15.05.2019 18:22

Большое спасибо, ребята, за вашу помощь @HCK

Theodory Faustine 15.05.2019 18:27

@TheodoryFaustine рад помочь. Хорошего дня

Kenny Horna 15.05.2019 18:28

Что делать, если в таблице около 100 тыс. записей? Вы делаете ->get(), который извлечет все записи в памяти.

Abhishek 04.02.2021 08:39

@Abhishek, конечно, в примере я сделал это простым способом, но проблема, которую вы подчеркиваете, реальна, если у вас есть тысячи записей (в памяти). В этом случае вы можете использовать курсоры/итераторы, которые теперь изначально поддерживаются с помощью класса LazyCollection. Подробнее об этом здесь.

Kenny Horna 04.02.2021 22:58

@KennyHorna ага. Я бы посоветовал вам добавить это и в свой ответ. Хотя бы просто предупреждение.

Abhishek 05.02.2021 08:13

Это непроверенное решение (которое потребует рефакторинга:

$groups = ['18-24' =>, '25-35', ..., '45'];

$applicants = User::applicant()->get();

$groups = collect($groups)
    ->map(function ($range, $key) use ($applicants) {
        $rangeLimits = explode('-', $range);

        $count = $applicants->filter(function ($applicant, $key) use ($rangeLimits) {
            $age = Carbon::parse($applicant->dob)->age;

            $verdict = $age >= $rangeLimits[0];

            if (isset($rangeLimits[1])) {
                $verdict = $age <= $rangeLimits[1];
            }

            return $verdict
        })->count();

        $range = ! isset($rangeLimits[1]) ? $range . '+' : $range;

        return [ $range => $count ]; 
    })->flatten()->all();

Сначала вам нужно создать массив нужных вам групп, последняя группа не должна иметь +.

Затем вы получаете всех претендентов.

Затем вы просматриваете каждую группу и выясняете, входят ли кандидаты в ее диапазон, и получаете подсчет. Это сопоставляется с результирующим массивом.

Спасибо, @thisisKelvin, но мой запрос не удался из-за переменной $max, нужно ли мне инициализировать ее значением 0?

Theodory Faustine 15.05.2019 18:04

@TheodoryFaustine Обновлено, должно было быть $rangeLimits[1],

thisiskelvin 15.05.2019 18:05

Большое спасибо @thisiskelvin

Theodory Faustine 15.05.2019 18:27

Попробуй это

$users =  \DB::table('users')
      ->select(DB::raw('concat(10*floor(age/10), \'-\', 10*floor(age/10) + 9) as `range`, count(*) as `numberofusers`'))
      ->groupBy('range')
      ->get();

Другие вопросы по теме