|
|
|
| Коллеги, прошу помочь.
Третий день горожу огород, но не выходит каменный цветок.
Имею два массива:
Первый простой массив, числовые ключи и значения
Второй массив — многомерный с непостоянной структурой и заранее неизвестной глубины.
<?
$array_one = array
(
'365' => '12',
'62' => '14',
'9' => '16',
'8' => '18'
);
$array_two = array
(
'0' => array
(
'147' => array
(
'5' => array
(
'62' => NULL,
'7' => array
(
'8' => NULL
),
'9' => NULL
),
'106' => NULL
),
'365' => NULL,
'4' => NULL
)
);
|
1) Нужно из первого массива $array_one взять значения и присвоить их таким же ключам во втором массиве $array_two.
2) Нужно у каждого элемента второго массива $array_two создать элемент «sum», содержащий сумму значений всех детей (в т.ч. и вложенных).
Т.е. нужно на выходе получить либо измененный второй массив $array_two, либо создать третий массив такого вида (опираясь на предложенный мною выше пример):
<?
$array_three = array
(
'0' => array
(
'sum' => '60', # сумма детей, т.е. 48+12 или 14+18+16+12
'arr' => array
(
'147' => array
(
'sum' => '48', # сумма детей, т.е. 48 или 14+18+16
'arr' => array
(
'5' => array
(
'sum' => '48', # сумма детей, т.е. 14+18+16
'arr' => array
(
'62' => array
(
'sum' => '14', # значение из $array_one: '62' => '14'
),
'7' => array
(
'sum' => '18', # сумма детей, т.е. только '8''sum' => '18'
'arr' => array
(
'8' => array
(
'sum' => '18' # значение из $array_one: '8' => '18'
)
)
),
'9' => array
(
'sum' => '16', # значение из $array_one: '9' => '16'
)
)
),
'106' => array
(
'sum' => '0',
)
)
),
'365' => array
(
'sum' => '12', # значение из $array_one: '365' => '12'
),
'4' => array
(
'sum' => '0',
)
)
)
);
|
| |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 00:10)
| | И по каким понятиям у ключа, например, 147 должен появится ключ "sum" равный 48? | |
|
|
|
|
|
|
|
для: confirm
(05.04.2013 в 11:32)
| | Смотрите:
У ключа 147 два прямых потомка: 5 и 106. Этим ключам нет соответствия в массиве $array_one, значит чисто их sum на этом этапе == 0.
Но у ключа 5 есть дочки: 62, 7 и 9.
У 62 и 9 есть соответствия в массиве $array_one, значит их «законный» sum берем оттуда: '62''sum' => '14', '9''sum' => '16'
А у ключа 7 нет соответствия в массиве $array_one, но у него так же есть дочка-ключ 8.
А у этой дочки 8 есть соответствие в массиве $array_one, значит '8''sum' => '18'
Это мы распределили собственные 'sum' по соответствиям из первого массива.
Теперь считаем суммы детей:
1) у ключа 7 будет 'sum' => '18' , т.к. у него у одной дочки '8''sum' => '18'
2) у ключа 5 будет 'sum' => '48' , т.к. у него 3 дочки:
'62''sum' => '14'
'9''sum' => '16'
'7''sum' => '18'
3) у ключа 147 будет 'sum' => '48' , т.к. у него 2 дочки:
'5''sum' => '48'
'106''sum' => '0' (т.к. ключу 106 не нашлось соответствия в первом массиве)
4) у ключа 0 будет 'sum' => '60' , т.к. у него 2 дочки:
'147''sum' => '48'
'365''sum' => '12' (соответствия из первого массива) | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 17:18)
| | Я не об этом, я вижу, что во втором массиве на некотором уровне есть ключи (а не дочери, нет в массиве ни дочерей, ни потомков) первого массива.
Я о другом. Представьте, что ваша перчатка, когда вы ее одеваете, колет вам кончик среднего пальца. Что вы будете делать, чтобы узнать в чем проблема:
а) начиная с края перчатки, будете просматривать каждый миллиметр ее внутренней стороны?
б) выверните перчатку наизнанку и определите проблему сразу?
Я не сомневаюсь, что вы будете поступать по варианту б). Вот так и с вашим массивом. В идеале ваш второй массив должен быть вывернут наизнанку, иначе при проходе его циклом (а поступать придется так), сложно будет понять, надо ли добавлять ключ sum текущему ключу. То есть, чтобы сформировать требуемое, нужно добраться до самого глубокого вложения, узнать есть ли ключи требуемые, и затем возвращаться вверх, добавляя необходимое.
Другими словами, структура второго массива очень неудобная для данной операции. Я возможно и не прав, но что-то подсказывает, что второй массив описывает некое вложение записей в базе данных, например, товаров в категориях, или комментарии к постам. Это так? | |
|
|
|
|
|
|
|
для: confirm
(05.04.2013 в 17:30)
| | Да, опыт Вас не подводит.
Ок, опишу сначала, может я действительно пошёл изначально не по верному пути.
1. Имеем таблицу в БД с 2 тысячами категорий услуг с глубокой вложенностью с обычной структурой id - id_parent - data.
2. Имеем таблицу в БД с 2 тысячами населенными пунктами с такой же структурой.
3. Имеем таблицу в БД с самими услугами.
Цель задачи - снизить нагрузку на sql-сервер при просчете количества услуг в каждой категории в каждом населенном пункте.
Как я думал это реализовать:
1) с помощью планировщика создаются (и регулярно переактуализируются) файлы с массивами для каждого населенного пункта
<?
$array_one = array
(
'365' => '12',
'62' => '14',
'9' => '16',
'8' => '18'
);
|
где ключи - это id категорий, а значения - количество наименований (услуг) в этой категории.
Далее я имею файл с массивом-деревом всех категорий - $array_two.
Далее я думал: при выборе юзером какого-то определенного нас.пункта я беру массив $array_one именного этого города $array_one, беру массив-дерево категорий $array_two, модифицирую второй $array_two и вывожу.
По замерам это намного быстрее и менее ресурсоёмко, чем осуществлять постоянный просчет средствами MySql.
Структура массивов была выбрана для экономии места на hdd.
В принципе можно структуру массивов "подкрутить".
Т.е., резюмируя, мне нужно получить массив с ключом-id_категории и значеним - количество наименований (услуг) в этой категории, беря это самое количество из первого массива.
Буду рад за идеи по решению моей задачи. | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 18:01)
| | Ну если меня он не подводит, то зачем весь этот сыр-бор?
Снять нагрузку, это один раз, при добавлении/удалении записи в базу, суммировать/вычитать значение уже имеющегося поля в таблице, которое содержит число записей (по умолчанию 0). Согласитесь, что операция добавления/удаления записи происходит намного реже, чем запросы на выдачу этих записей. То есть при выдаче вы уже можете получать готовое, а не заниматься никчемным. | |
|
|
|
|
|
|
|
для: confirm
(05.04.2013 в 18:17)
| | Наименования (услуги) для каждого населенного пункта свои.
Поэтому количество наименований (услуг) в каждой из категории будет разным, в зависимости от выбранного пользователем населенного пункта.
А иначе да - можно было б попросту завести столбец в категориях с количеством этих услуг... | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 18:56)
| | А причем тут для каждого разные? Хотите сказать, что указывая для субъекта А некий набор, нельзя посчитать его сумму и записать ее в базу, но при этом получая этот набор, воткнув его в промежуточный массив, это можно сделать? Я так полагаю, если есть набор и известна его сумма, то выбирая такие наборы из таблицы остается только просчитать их сумму на выходе.
Зайдите в раздел MySQL, опишите структуру данных, и как поступить для получения результата необходимого. Уверен, что ваш подход изначально неверен. | |
|
|
|
|
|
|
|
для: confirm
(05.04.2013 в 19:31)
| | Я не много не понял Ваши слова и, возможно, решение лежит на поверхности, но я его не вижу, к сожалению.
Смотрите:
Есть таблица услуг:
id_item......id_category......id_location......data........
Есть таблица категорий:
id_cat......parent_cat......data........
Есть таблица стран--областей-городов:
id_loc......parent_loc......data........
Средствами MySql и парами циклов всё очень просто высчитывается и на страницу выводится. Проблема при этом одна - бесчисленное кол-во sql-запросов. Отсюда возникают другие две проблемы: повышенная ресурсоёмкость и большое время генерации данных.
Т.е. когда город у юзера не выбран, то всё считается не беря в расчёт столбец id_location.
А вот когда у юзера выбран город, то нужно выводить на страницу дерево категорий, опираясь на столбец id_location из таблицы услуг.
Опять же повторюсь: sql-запросами и парами циклов все это без проблем делается, но очень долго и ресурсоемко.
Поэтому я не пошёл в раздел MySql.
Поэтому в качестве оптимизации я принял решения:
- единожды сделать "тыщу" запросов для генерации всего дерева категорий-субкатегорий и записать это в файл;
- раз в сутки пересчитывать счетчик позиций (услуг) в каждой субкатегории, беря во внимание конкретный город (столбец id_location из таблицы услуг) и так же записать это в файлы (для каждого города свой файл).
И при генерации брать файл с массивом дерева категорий, брать "городской" файл с массивом в котором находятся счётчики объявлений в каждой категории и генерировать массив, который потом и рисовать на странице.
Вот с этим и возникли у меня проблемы.
Конкретно даже - возникли проблемы с рекурсивным подсчетом позиций в дочерних субкатегориях и присваивания полученной цифры в какой-то ключ ('sum') родительской категории. И так подниматься выше и выше по массиву. | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 20:01)
| | >единожды сделать "тыщу" запросов для генерации всего дерева
Надо сказать, это тоже не хилая нагрузка, как вы думаете?
Здесь вообще-то РНР раздел, желания долго обсуждать оптимальную структуру mysql-данных под частые задачи не место. Просто мне кажется, что эта структура не очень удачная, либо не все учитывает, и как следствие этого "возникли проблемы с рекурсивным подсчетом позиций в дочерних субкатегориях".
Ну вы же понимаете, что хоть mysql-запросами, хоть php средствами, переварить такую неудобную структуру это не лучший вариант. Тем более если дерево, это "тыщи".
Если у какого-то пользователя А, есть набор, то ведь можно посчитать сумму его и хранить. Можно ведь хранить не только конечную сумму, но и сквозную, по иерархии, нужна только таблица связей, или таблица сумм сквозных. Как именно сказать трудно, поэтому и предлагаю в раздел MySQL, и там обсудить все более обстоятельно, исходя из подробного описания данных.
На РНР сделать можно, конечно, для этого достаточно внешнего по отношению к циклу массива, в котором должны запоминаться ключи при проходе исходного массива вглубь. Если конечное вложение имеет ключи исходные, то запомненным ключам во внешнем массиве указываем значение суммы (специально добавлять ключ sum нет необходимости). Нет проблем сделать реверс этой ветви запомненной, чтобы произвести такое присвоение значений. Если же конечное вложение не имеет искомых ключей, то данная ветвь удаляется из внешнего массива.
Если некоторый уровень имеет несколько вложений на каком-то уровне, значит во внешнем массиве должен быть уже такой же уровень, но с другим ключом. То есть лучше на проходах не добавлять ключ sum, а запоминать уровень каждого ключа, чтобы легко можно было определить есть ли уже во внешнем массиве некий ключ этого же уровня.
Вот что-то в таком плане. Но перебирать весь массив из "тыщ" ветвей "резинового" размера, это тоже не лучшее решение. Я просто полагаю, что наборы не для каждого пользователя индивидуальны, и даже не для дома, в котором он проживает, и не улицы, квартала... и если это город, то значит можно все это уже держать готовым, вряд ли ваша база для всего мира. И не нужно будет тысяч запросов, достаточно будет одного. | |
|
|
|
|
|
|
|
для: confirm
(05.04.2013 в 20:33)
| | >единожды сделать "тыщу" запросов для генерации всего дерева
>>Надо сказать, это тоже не хилая нагрузка, как вы думаете?
Это делается всего один раз в жизни, поэтому не критично.
>> ...вряд ли ваша база для всего мира...
Именно для всего мира, к сожалению. Полная иерархия:
Россия =>
-- Адыгея =>
------ Адыгейск
------ Майкоп
------ ...
-- Алтайский край =>
------ Акташ
------ Акутиха
------ ...
-- ...
Австралия =>
-- Виктория
------ Балларат
------ Бендиго
...
...
|
И, к сожалению, я не волен выбирать структуру БД, т.к. пытаюсь оптимизировать уже изготовленный скрипт с несколькими сотнями тысяч позиций, распределенных по 2 тысячам категорий и несколькими тысячами нас.пунктов.
Поэтому, собственно, и упираюсь Вашим словам по переходу в форум mysql и инициации нового "разбирательства" :(
Остается мне работать с массивами php.
Да, я могу сгенерировать промежуточные массивы ($array_one со счетчиками и $array_two с деревом категорий) любой структуры. Лишь бы получилось решить задачу.
И да - можно изменить структуру выходного массива, вплоть даже на одномерный без деревьев, но лишь бы в значении ключей родительских категорий было бы кол-во позиций дочерних, например:
<?
$array_three = array
(
'0' => '60',
'147' => '48',
'5' => '48',
'62' => '14',
'7' => '18',
'8' => '18',
'9' => '16',
'106' => '0',
'365' => '12',
'4' => '0',
);
|
в любом порядке.
Что бы я потом, при выводе на страницу категорий_субкатегорий мог бы вывести этот счётчик
<?
echo '<span>Категория: '.$category_name.'</span>';
if(array_key_exists($category_id, $array_three))
{
$count = $array_three[$category_id];
}
else
{
$count = '0';
}
echo '<span title="Количество наименований: '.$count.'">'.$count.'</span>';
|
Help me...
P.S. Мне вот интересно как устроен такой механизм у других. Например на досках объявлений схожий момент: попробуйте на irr.ru изменить свой нас.пункт - сразу изменится счётчик объявлений в категориях. Я просто уверен, что они не просчитывают это средствами БД при каждом заходе каждого юзера. | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 22:59)
| | Вот у меня Россия => Адыгея => Адыгейск ..., ну согласитесь, что это не полная картина того, что есть на самом деле.
Бог с ним, будем предполагать, что в пределах одной ветви ключи уникальные. Тогда незачем их вкладывать по иерархии категорий, достаточно знать ключ и значение ключа (сколько записей).
<?
echo '<pre>';
$a = array(
1 => array(23=>array(27=>array(123=>8))),
7 => array(33=>array(47=>array(223=>array(475=>12, 700=>24)))),
5 => array(33=>array(66=>array(98=>6)))
);
print_r($a);
$n = array();
foreach($a as $k=>$v) {
while(is_array(current($v))) {
$n[$k][] = key($v);
$v = current($v);
}
$n[$k] = array_fill_keys($n[$k], array_sum($v));
$n[$k]['services'] = $v;
}
echo '<br>result:<br>';
print_r($n);
echo '<br>total: '.array_sum(array_map('current', $n));
|
Если же в пределах ветви ключи не уникальны, значит надо делать вложением, что в общем-то тоже не проблема. Последнее вложение в результирующем под строковым ключом, иначе оно при таком добавлении будет получать ключ на единицу больше предыдущего, и если опираясь на ключи меню получать из этого массива значения, то будет естественно ошибка. Но можно (если без вложения по иерархии), разбивать массив ключей до последнего вложения, а затем добавлять (чтобы иметь только ключи ветви):
<?
//после цикла while
$n[$k] = array_fill_keys($n[$k], array_sum($v));
$n[$k] = array_chunk($n[$k], 1, true);
$n[$k][] = $v;
//а общее число записей, тогда так:
echo '<br>total: '.array_sum(array_map('current', array_map('current', $n)));
|
Это для прохода по всему массиву. Но пользователь не может сразу быть в нескольких местах, значит обрабатывать нужно всего одну ветвь (судя и по вашему примеру), тогда будет проще. Но с другой стороны, в вашем примере, если переложить все на города, то получается два города в ветви. Не понятно, выводить надо для страны/областям/городам? Большая портянка а не меню... К тому же, если административное деление это страна->область->город, то откуда взялась "произвольная глубина вложения"? Получается что она фиксированная, и равна трем. А если так, опять проще.
Я не люблю гадать, а конкретного я не знаю. | |
|
|
|
|
|
|
|
для: confirm
(06.04.2013 в 03:11)
| | confirm - что-то не смоглось приспособить Ваши примеры :(
Но за помощь огромное спасибо.
Почти готовую функцию мне написали на php.ru: http://php.ru/forum/viewtopic.php?p=353055#p353055
А Nested sets мне не подходит, т.к., как уже выше говорил - я не волен менять структуру БД, т.к. проект, фактически написан и я всего лишь пытаюсь оптимизировать то что есть :( | |
|
|
|
|
|
|
|
для: an0n
(07.04.2013 в 19:15)
| | Посмотрел, что вам приготовили, слишком много, да еще с рекурсивным обходом, а он не нужен.
Я исходил из того, что незачем иметь какой-то массив первый по которому выбирать во втором. Нужно при запросе данных помещать сразу id и количество услуг во второй массив (а это сделать ведь не сложно, коли вы получаете это первым массивом).
Я не стал вычислять только общую сумму по уровню вверх, а сделать это просто с помощью array_map/array_sum уже для всего уровня (как это делается при конечном вложении в примере). Не стал писать этого в примере, как не могу себе представить, что в некотором государстве ветвь административного вложения была бы более 4, но вы утверждаете, что "безразмерная". Зря же писать рекурсию (хотя она и тут совсем не нужна), какой смысл.
Все, а иметь такой результирующий ужас как [0_147_5_summ] => 48, это к чему? Ведь у вас, как я понял выбирается сразу все - id, описание и прочее для меню. Значит при запросе меню этого (или его ветви), достаточно по этому id (выбрать из массива организованного как id -> количество записей) его значение, без разбора строкового ключа (у вас два массива в итоге, но вместо ключей корявость).Ну что проще? 5 МБ со 500000 строк (да еще преобразовать в массив их) да загрузить такое, да еще иметь вместо ключей id, портянки типа 0_147_5_summ.... Было бы три строки, другое дело.
Ну не поняли идею, нравится то что вам написали, ну пользуйтесь, не мне же ) | |
|
|
|
|
|
|
|
для: confirm
(07.04.2013 в 19:30)
| | >> Нужно при запросе данных помещать сразу id и количество услуг во второй массив (а это сделать ведь не сложно, коли вы получаете это первым массивом).
Вы правы, если работать динамически, т.е. при генерации каждой страницы выбирать всё дерево категорий_субкатегорий из БД и присваивать этим ID количество записей.
Но смысл моей деятельности заключается в том, что бы исключить "тыщи" (точнее ~160 на сегодняшнем этапе) sql-запросов для выстраивания дерева. Т.е. при работе с БД всё равно понадобятся рекурсивные проходы и подсчёт. Но только уже с использованием sql-сервера.
Я же это сделал один раз ($array_two) и положил в файл на hdd.
И планировал делать те же рекурсивные циклы, но только без участия sql-сервера.
Вот и изобретаю велосипед :(
А структура результирующего массива не важна.
Главное, что бы при выводе категорий на страницу я смог бы "дернуть" ключ из результирующего массива и вывести этот счётчик из значения.
Конечно, желательно, что бы первая функция (из поста php.ru/forum/viewtopic.php?p=353055&sid=4c0ddf546cf9ea38e8f106d3c1eab6b7#p353055 ), которая осуществляет просчет и делала бы одномерный массив, что бы избежать включения моей второй функции (из поста php.ru/forum/viewtopic.php?p=353119&sid=4c0ddf546cf9ea38e8f106d3c1eab6b7#p353119 ). А то приходится еще раз рекурсивно прогонять массив.
Но я этого победить, пока, не смог :(
>> не могу себе представить, что в некотором государстве ветвь административного вложения была бы более 4, но вы утверждаете, что "безразмерная". Зря же писать рекурсию (хотя она и тут совсем не нужна), какой смысл.
Вы правы: на данном этапе структура 3-х ступенчатая. Но в планах стоит внедрение большей глубины, например:
Россия => Московская область => Люберецкий район => Люберцы
Россия => Республика Алтай => Чемальский район => Чемал
Какова будет итоговая глубина и будет ли она одинакова для каждого из субьектов - я не знаю, поэтому пытаюсь заунивесалить механизм.
Поэтому я и не понял Вашу идею и примеры кода. | |
|
|
|
|
|
|
|
для: an0n
(07.04.2013 в 20:03)
| | Да, это так - ввиду занятости, либо читая вопрос, но думая над своими вопросами, и по иным причинам, я могу читать пост бегло, но при этом стараюсь выявить главное в нем, или странности. Я признаю, что в этом случае я могу допустить и ошибку, это естественно.
Но я заострил свое внимание на некоторых моментах ваших постов, из которых и строил свои предположения, а на них код примера. Вы к сожалению на мои предположения не реагировали, так что будем считать, что молчание знак согласия.
А теперь я эти моменты из ваших постов, свои предположения, которые строились на этих моментах и мысли сопутствующие, вопросы которые при этом возникали, все это изложу по шагам, вам только нужно отметить в чем мои предположения были верны или нет.
Предположение 1. Есть таблица, которая описывает административные единицы.
Предположение 2. Есть таблица описывающая услуги.
Предположение 3. Первая и вторая таблицы связаны по ID.
Момент 1. Вы выбираете все записи для меню, так что в итоге у вас получается массив описывающий дерево вложений. (назовем его массивом А)
Момент 2. Вы выбираете сумму услуг в отдельный массив. (назовем его массивом В)
Мысль 1. Зачем строить массив В, если при выборке дерева для массива А, конечные их вложения ссылаются на таблицу услуг, и для этого конечного вложения уж можно посчитать (для одного города) число услуг, записав это под ID услуги в массив А. Другими словами, последнее вложение (либо его элементы) это не массив, а ключ -> значение, в отличии от предков в дереве, которые всегда будут массивами (можно и не считать, все равно, по идее, конечно ID вложения, это ID услуги).
Момент 2. Вы выбираете эти записи из таблицы рекурсивно.
Предположение 4. Если рекурсивный выбор, значит Предположение 1 верное.
Если Момент 2 и Предположение 1 истинны, то из этого вытекает:
Предположение 5. Каждое ID всего дерева, это уникальные значения. Возможно за исключением самого верхнего уровня (страны, которые могут быть в отдельной таблице, что в итоге все равно не влияет на подход к решению задачи).
Вопрос 1. Зачем строить массив сумм услуг (назовем его массивом С) с ключами в которых ключ это строка ключей массива А, если каждый ID дерева уникален согласно Предположению 5.
Вопрос 2. Зачем нужен рекурсивный обход вложения, если конечный элемент вложения, это не массив (согласно Мысли 1). Для этого нужно просто пройтись циклом while до конца вложения - до достижения его элемента не являющегося массивом.
Резюме. Для того чтобы обойти массив А и узнать сумму услуг его ветвей, считая при этом, что массив А в конечном вложении (для города) эта сумма уже посчитана и содержится, нужно:
а) цикл прохода по первым ключам массива, при этом эффективнее использовать цикл for(), обходя массив с двух сторон, обрабатывая сразу два его крайних верхних ключа (от краев массива вглубь).
б) вложения проходить циклом while справа налево, записывая в каждой итерации во внешний массив С ID дерева для текущего на на момент итерации цикла for() ключа.
в) после каждого прохода вложения:
в1) просчитывать сумму всех услуг (для города), залив этим значением полученный массив ключей дерева (итог ID -> сумма услуг)
в2) посредством array_sum/array_map посчитать сумму полученных ветвей текущего на момент итерации цикла for() - для позиций end-1, prev и current
г) по окончании цикла for() просчитать сумму верхних ключей массива С
д) при построении меню по массиву А, получать из массива С значение записи для ID дерева по ID ключам массива А.
То есть массив С, это каждый его элемент массив без вложений, элементы которого, это ID->сумма, так как все ID уникальны. Достаточно обратиться по ключу чтобы получить сумму.
Как вариант, не строить массив С в полном объеме, а только для вложений ключа страны (на время его обработки). После просчета их на всех уровнях переписать значения в массив А, ужу под ключом sum. | |
|
|
|
|
|
|
|
для: confirm
(07.04.2013 в 22:28)
| | Боюсь, что я опять Вас "не слышу". А скорее мы с Вами говорим немного о разном. Тем не менее попробую изложить свои мысли.
>> Мысль 1. Зачем строить массив В, если при выборке дерева для массива А, конечные их вложения ссылаются на таблицу услуг, и для этого конечного вложения уж можно посчитать (для одного города) число услуг, записав это под ID услуги в массив А.
Совершенно верно.
Но эту работу (а так же махинации, предложенные Вами ниже) придётся
а) либо делать при каждой генерации страницы, что делается сейчас и так, создавая те пресловутые "тыщи" sql-запросов и циклов.
б) либо как-то хранить в кэше (в моём случае выбран hdd).
Если задача стоит в исключении работы с sql-сервером, а именно эта задача и стоит перед нами, то остается вариант "б".
Но, если следовать Вашему предложению и писать в массив категорий_субкатегорий в качестве конечных значений количество позиций, то мне нужно будет работать (хранить, обновлять) с массивами в количестве равному количеству административных субъектов.
А это, на данном этапе (т.е. когда еще дерево субъектов сформировано не до конца) получается ~ 15000 файлов на hdd. 15 тысяч файлов кэша по ~20kb.
А смысл?
Я и так буду хранить такие файлы (с массивами $array_one), но не по 20kb, а по 1-2.
И то не в полном количестве 15 тысяч, а только для тех субъектов, в которые "ходят" пользователи.
Поэтому я пораскинул мозгом налево-направо и выработал, как мне тогда показалось, не плохой вариант:
При первичном выборе юзером определенного субъекта скрипт создаёт кэш-файл с массивом $array_one и записывает его на hdd и ежесуточно CRONом актуализировать этот массив со счётчиками.
Разумеется, я не исключаю такой вариант, что мой вариант не идеален, но поставленная задача решена и работает всё, довольно, быстро: вывод страницы с категориями и счетчиками получается за 0.0411 сек. и ноль sql-запросов.
Меня это катастрофически устраивает.
Позволю себе поместить сюда код, который дали мне на php.ru:
<?php
$array_one = array(
'365' => '12',
'62' => '14',
'9' => '16',
'8' => '18'
);
$array_two = array(
'0' => array(
'147' => array(
'5' => array(
'62' => NULL,
'7' => array(
'8' => NULL
),
'9' => NULL
),
'106' => NULL
),
'365' => NULL,
'4' => NULL
)
);
function get_count(&$array, $array_one, &$result) {
$summ = 0;
foreach ($array as $key => &$val) {
if (is_array($val)) {
$result[$key] = get_count($val, $array_one, $result);
} else {
if (isset($array_one[$key])) {
$val = $array_one[$key];
}
if ($val === null) {
$val = 0;
}
$result[$key] = $val;
}
$summ += $result[$key];
}
$array['summ'] = $summ;
return $summ;
}
$result = array();
$total = get_count($array_two, $array_one, $result);
echo '<pre>';
print_r($total); // общая сумма
print_r($result);
|
На выходе получаю желанный массив
Array
(
[62] => 14
[8] => 18
[7] => 18
[9] => 16
[5] => 48
[106] => 0
[147] => 48
[365] => 12
[4] => 0
[0] => 60
)
|
Еще раз Вам спасибо за участие в поиске решения моего вопроса! | |
|
|
|
|
|
|
|
для: an0n
(05.04.2013 в 22:59)
| | B все же я бы изменил БД....
Тем более, что изменять кардинально ее не нужно.
Нужно изменить структуру ваших деревьев id->parent_id на чуть более усложненную: Nested Sets
В таких деревьях можно без рекурсии выбирать все дочернее подмножество, следовательно можно все подсчитать одним запросом на уровне СУБД без рекурсий и прочей лажи.
Уверен, что на сайтах типа irr, avito, market.yandex именно так все и устроено. И считается не раз в сутки, а именно при каждом запросе (ну за исключением кеширования, конечно). | |
|
|
|
|