Сортировка многомерных массивов

Обсуждение серверного программирования.

Модераторы: Duncon, Yurich

Ответить
REZER
Сообщения: 2
Зарегистрирован: 09 окт 2009, 02:16

В общем задача такая: необходимо из файла (база данных) выдать массив с уже разбитыми ячейками и полностью отсортированной. Всё будет делать функция, но в примере показываю просто алгоритм:

Код: Выделить всё

// База данных (по идеи, читается из файла)
$array = array();
$array[0] = "98|2009-10-09 2:48:29|211.138.124.228";
$array[1] = "101|2009-10-09 2:49:39|87.98.143.239";
$array[2] = "106|2009-10-09 2:50:08|189.21.54.50";
$array[3] = "105|2009-10-09 2:50:34|195.158.1.19";

$sort = 1; // По какой ячейке сортировать
$desc = true; // true - в обратном порядке, false - по проядку
$separator = "|"; // Разделите ячеек базы данных
$sort_array = array(); // Временное хранилище, которое и будем сортировать
$return_array = array(); // Массив, который в конце работы возвратит функция
for( $i = 0; $i < count( $array ); $i++ )
    {
        // Читаем запись базы данных и какдаем в массив
        $array[$i] = explode( $separator, $array[$i] );
        // С тем же ключём, что и выше помещаем нужную ячейку для сортировки
        $sort_array[$i] = stripslashes( $array[$i][$sort] );
    }

// Смотрим на способ сортировки
if( $desc )
    {
        // Сортируем в обратном порядке
        arsort( $sort_array );
    }
        else
    {
        // Сортируем по порядку
        asort( $sort_array );
    }

// Перемалываем ключи
reset( $sort_array );

// Уже в пустой массив (ключ имеется в виду) кидаем таблицу базы данных
foreach( $sort_array as $key => $value ){ $return_array[] = $array[$key]; }
// Ну а это мы просто выводим для проверки (потом удалим конечно)
foreach( $return_array as $key => $value ){ echo "{$key} - {$value[$sort]}
"; } 
Каждая ячейка массива "array (базы данных)" содержит в себе ещё по массиву со многими значениями. Задача отсортировать весь лист массива ( то есть array[0], array[1] и т.д) "array (базы данных)" по дате (допустим).

Впринципе с 100-ей таблиц мой способ написанный выше справится быстро. Но их будет не сотни, а сотни тысяч и может больше (поэтому от MySQL я отказался). Дак вот вопрос, есть ли спец. функция в PHP, чтобы выполнить такое, или как можно попроще выполнить такую операцию? Если не совсем понятно, то необходимо выполнить сделать то же самое, что и в MySQL:
SELECT * FROM `база` ORDER BY `date` DESC
При тесте в ровно 50000 строк, данный код справляется за 1.2 сек, в то время кода Mysql с тем же объёмом базы данных и тойже сортировкой почти не тратит на это время. Самые длительные операции в данном скрипте:

Код: Выделить всё

$sort_array[$i] = stripslashes( $array[$i][$sort] ); - Тратит на всё про всё 0.6 сек.
$array[$i] = explode( $separator, $array[$i] ); - Тратит на это 0.5 сек. 
От MySQL решил отказаться только потому, что 50000 записей весят порядком 5 МБ. Добавление записей можно производить раз в день (или дольше) вручную (до этого использовать кэш), здесь нет особой необходимости.

Вот написал функцию, может так понятней будет:

Код: Выделить всё

function ReturnArrayStats( $array, $start = 0, $limit = 10, $sort = 0, $desc = true, $separator = "|"  ){
    
    $sort_array = array(); // Временное хранилище, которое и будем сортировать
    $return_array = array(); // Массив, который в конце работы возвратит функция
    
    for( $i = 0; $i < count( $array ); $i++ )
        {
            $array[$i] = trim( $array[$i] );
            // Читаем запись базы данных и какдаем в массив
            $array[$i] = explode( $separator, $array[$i] );
            // С тем же ключём, что и выше помещаем нужную ячейку для сортировки
            $sort_array[$i] = stripslashes( $array[$i][$sort] );
        }
    
    // Смотрим на способ сортировки
    if( $desc )
        {
            // Сортируем в обратном порядке
            arsort( $sort_array );
        }
            else
        {
            // Сортируем по порядку
            asort( $sort_array );
        }
    
    // Перемалываем ключи
    reset( $sort_array );
    
    // Уже в пустой массив (ключ имеется в виду) кидаем таблицу базы данных
    $i = 0;
    $i_limit = 0;
    foreach( $sort_array as $key => $value )
        {
            if( $i >= $start )
                {
                    if( $i_limit < $limit )
                        {
                            $return_array[] = $array[$key];
                            $i_limit++;
                        }
                            else
                        {
                            break;    
                        }
                }
                
            $i++;
        }
    
    return $return_array;
}

// База данных
$array = file('bd.txt' );
$return_array = ReturnArrayStats( $array );

// Ну а это мы просто выводим для проверки (потом удалим конечно)
foreach( $return_array as $key => $value ){ echo "{$key} - {$value[1]}
"; } 
Файл bd.txt:
98|2009-10-09 2:48:29|211.138.124.228
101|2009-10-09 2:49:39|87.98.143.239
106|2009-10-09 2:50:08|189.21.54.50
105|2009-10-09 2:50:34|195.158.1.19
Место операции "for" пробовал "while" и "foreach" - не помогает, времени затрачивает абсолютно одинкаво. "ArrayMultiSort" - не даёт нужного результата.

Блин ну люди, должен же хоть кто-то что-то знать на счёт этого. Я 5 часов гуглил, было похожее, но совсем не то. Там была сортировка по всем ячейкам массива, а мне надо по конкретной и расчитывать на все данные, а не только по двум массивам. Мне нужно хотябы оптимизировать один процесс, который тратит 0.6 сек.
Skvor
Сообщения: 17
Зарегистрирован: 30 сен 2009, 21:14

Чесно говоря я слабо все понял. Тебе требуется оптимизация, ну тогда попробуй все хранить не в базе а в файле. Возможно это уменьшит скорость загрузки. Больше не знаю, что предложить.
atavin-ta
Сообщения: 585
Зарегистрирован: 30 янв 2009, 06:38

Думаешь, СУБД не оптимизированы для таких задач? Надеешься оптимизировать лучше? Если уж завёл БД, то всё, что требует оптимизации, поручай (с целью оптимизации) СУБД, а что не требует, или для чего в СУБД нет готовой стандратной функции, делай сам. А если СУБД тебя не устраивает, то зачем тебе БД? Делай всё сам, включая хранение. Иначе добавшь тормозов в момент выборки, которыми гарантировано скомпенсируешь любые преимущества, которые ты надеешься получить за счёт оптимизации своего кода.
&quot писал(а):Место операции "for" пробовал "while" и "foreach"
.
Чего и следовало ожидать. Оптимизация цикла это:
1. Сравнение с нулём и старт с числа, а не наоборот как у тебя.
2. Префиксный инкремент/декремент вместо постфиксного, если в языке предусмотрены обе формы и если между ними есть хоть какое то различие, кроме синтаксического.
Но большого эффекта от этого не жди. Лучше выбери хороший метод сортировки. Оптимальная сортировка плохим методом, например, пузырьком, может занимать на порядки больше времени, чем хорошим методом, но с искусственными тормозами. Истинно же оптимальный вариант - одновременное применение и оптимизации кода, и хорошего метода самой сортировки.
Вопрос: "Почему вы все сионисты? Нельзя ли писать на чём то другом?".
Ответ: "Писать можно на чём угодно. Но зачем же так себя ограничивать? Пиши на С!".
REZER
Сообщения: 2
Зарегистрирован: 09 окт 2009, 02:16

Думаешь, СУБД не оптимизированы для таких задач?
Естественно оптимизированы, это я уже понял после того, как испытал на её на примере. Когда СУБД почти не затратила времени, а мой скрипт повис загрязнив всю выделенную php память. Но дело не в том, просто в MySQL 60 000 тех же строк, занимают порядком 20 МБ, а в файле 100 000 строк всего 6 МБ. Строк может быть и более миллиона и ещё больше. А базу заполнять такими объёмами всякой ерундой не очень охото. Впринципе данная таблица должна хранить записи показов, что почти не используется, а если уж используется, то данные записи нужны.

Единственное, что крупно снизило время генерации и очистку оперативки, это очистка не нужных переменных в самой функции. Я удивился, но сократилось почти в 2 раза.
Но большого эффекта от этого не жди. Лучше выбери хороший метод сортировки. Оптимальная сортировка плохим методом, например, пузырьком, может занимать на порядки больше времени, чем хорошим методом, но с искусственными тормозами. Истинно же оптимальный вариант - одновременное применение и оптимизации кода, и хорошего метода самой сортировки.
Вот это то я и ищу, как бы пооптимизированней отсортировать всё это дело.
atavin-ta
Сообщения: 585
Зарегистрирован: 30 янв 2009, 06:38

Метод Шелла попробуй. И еще алгоритм быстрой сортировки (так и называется). Герберт Шилдт. По-моему, "Теория и практика С++".
Вопрос: "Почему вы все сионисты? Нельзя ли писать на чём то другом?".
Ответ: "Писать можно на чём угодно. Но зачем же так себя ограничивать? Пиши на С!".
anawsCreend
Сообщения: 11
Зарегистрирован: 09 дек 2009, 15:31
Откуда: Россия
Контактная информация:

Всем привет, есть проблема...
у меня есть проблема с сортировкой результатов...
у меня передается в скрипте имя столбца по которому сортируется... но есть проблема...
в базе есть 2 столбца цена и цена со скидкой как сделать, чтобы если поле цена со скидкой не равно 0, то сортировалось по нему, а если оно равно 0, то по полю цены ?
Хыиуду
Сообщения: 2442
Зарегистрирован: 06 мар 2005, 21:03
Откуда: Москва
Контактная информация:

&quot писал(а):Но дело не в том, просто в MySQL 60 000 тех же строк, занимают порядком 20 МБ, а в файле 100 000 строк всего 6 МБ. Строк может быть и более миллиона и ещё больше
И что, гигабайта для милионной базы жалко?
В одной статье была хорошая фраза: "Сейчас компьютерное железо стоит дешевле, чем труд программиста".
Искусство программирования - заставить компьютер делать все то, что вам делать лень.
Для "спасибо" есть кнопка "Спасибо" в виде звездочки внизу под ником автора поста.
Ответить