Сложная сортировка массивов на PHP

Недавно попросили написать скрипт для сортировки данных. Задача довольно простая. Есть многомерный массив. Его нужно отсортировать по трём определённым элементам.

Вначале я по привычке погуглил, но нашёл или монстрообразные или нерабочие решения. Поэтому пришлось писать скрипт самому. А решение оказалось очень простым.

Дано

На входе у нас текстовая база данных database.csv, записи которой разбросаны как попало. Нам нужно отсортировать записи по 3 параметрам, а затем записать в новый файл new_database.csv.

Для примера возьмём простенькую БД (см. ниже). Нам нужно отсортировать данные по стране, затем по городу, и затем по улице. Другие поля для наглядности опустим, но их может быть сколько угодно.

|||Aвстрия|Вена|Рокоссовского|
|||Россия|Москва|Петровка|
|||Украина|Чернигов|Валенка|
|||Aвстрия|Вайберг|Симонова|
|||Россия|Адлер|Кучмы|
|||Россия|Москва|Яйцево|
|||Украина|Киев|Ющенко|
|||Украина|Прилуки|Дятлова|
|||Россия|Москва|Путина|
|||Россия|Москва|Склокино|
|||Aвстрия|Фельдбах|Фейрштрассе|
|||Россия|Москва|Жадино|
|||Россия|Москва|Ахтунгово|
|||Украина|Чернигов|Морозова|

Решение

Решение задачи очень простое. Используем функции usort и strnatcmp. Не знаю даже, что здесь можно рассказывать, поэтому просто привожу код.

Весь смысл функции сортировки в том, что мы вначале сравниваем по одному параметру. Если они равны, то по другому. А если и они равны, то по третьему. Прелесть данного решения в том, что оно очень простое, легко внедряется куда угодно и может работать с любым количеством параметров.

<?php

// подгружаем файл
$data = file('database.csv');

// заполняем массив данными
foreach ($data as $string)
{
    // разбиваем строку
    $database[] = explode('|', $string);
}

// функция сортировки
function cmp($a, $b)
{
    // в первую очередь сравниваем по стране
    if ($a[3] != $b[3])
        return strnatcmp($a[3], $b[3]);
    // затем сравниваем по городу
    elseif ($a[4] != $b[4])
        return strnatcmp($a[4], $b[4]);
    // и наконец сравниваем по улице
    else
        return strnatcmp($a[5], $b[5]);
}

// сортировка базы данных
usort($database, 'cmp');

// собираем данные в строку
foreach ($database as $key => $string)
    $new_data .= implode('|', $string);

// запись в файл
file_put_contents('new_database.csv', $new_data);

Если нужно сравнивать строки независимо от регистра, то нужно использовать функцию strnatcasecmp.

За решение этой задачи у моего знакомого фрилансеры попросили 4000 рублей. Как думаете, стоит оно того?

И конечно комментарии приветствуются.

В рамках обмена

Многие вебмастера любят обвесить свои сайты разнообразными флешечками и рюшечками (их ещё называют свистелками и перделками). И конечно же заказчики обожают такие спецэффекты. Поэтому в вебмастеркой блогосфере очень популярны подборки jQuery скриптов. Читайте пост по ссылке и узнаете о существовании целых 10 украшений для вашего сайта.

Подпишитесь на обновления блога

Получить в подарок мини-книги и 21-дневный тренинг по личностному росту.

Подписаться на рассылку «Инструменты Интернет для онлайн бизнеса»

Поделиться ссылкой:


Комментарии:

20.01.2011 10:45:40

Думаю врятли это столько стоит, максимум 2к, хотя все зависит от значимости данного решения.

20.01.2011 10:55:44

Раз есть спрос за такую цену - значит, столько и стоит. :) Ну а в производительности, думаю, шустро работает. Возьму на заметку.

20.01.2011 11:01:09

Я думаю стоит, человек который может это быстро сделать должен еще знать свою цену

20.01.2011 11:05:00

Чувак. Фрилансеры не от хорошей жизни фрилансеры. А ты даешь им задачу, а потом делаешь загогулину - мол, «а я и сам могу, пардонь-те!» Эх эх эх.

20.01.2011 11:26:28

Игорь, согласен конечно. Но возможно они неправильно её оценили или загнули цену, так как не знали решения задачи.

Zorg, а я не давал им задачу. Мне задачу знакомый подкинул и сказал сколько за неё просят. Я её решил для интереса.

Да и причём тут хорошая-плохая жизнь? Я фрилансом занимаюсь, потому что мне так нравится.

20.01.2011 12:35:59

Пойду регистрироваться на фриланс сайтах, за такие деньги такие несложные задачи решать... :) Кстати, в цену можно добавить популярность кодера или репутацию, может поэтому такая цена. Хорошая репутация залог качественной работы.

20.01.2011 12:40:05
#7 AS

Думаю стоит - все зависит от реализации, тем более что в нашем примере для наглядности остальные параметры убраны. Цена она от много зависит)
Другое дело, сколько он по времени сказал это будет делать)

20.01.2011 14:35:33

Never Lex ну ты крут батька. Для понта решаешь детские задачки и постишь об этом в блог. Асталависта :)

20.01.2011 16:35:01

Zorg, да причём тут крутость. Просто интересно стало. Я не считаю себя гуру программинга, поэтому мне интересно делать некоторые вещи. Да и интересно стало, как уважаемая публика считает, стоит ли такая задача запрошенных денежек.

20.01.2011 16:45:49

отличное решение на основе встроенной функции, в духе php. что мешает хранить данные в *sql базе?

20.01.2011 20:11:21

webpavilion, предубеждения владельца сайта мешают.

20.01.2011 20:45:56

f-duck, спасибо за полезную ссылку!

20.01.2011 21:02:38
#14 f-duck

И да, чем был плох array_walk?

20.01.2011 21:13:26

f-duck, да ничем в принципе. А разве эта функция здесь более к месту?

21.01.2011 07:34:07

Задача, полюбому, коммерческой тематики. И если обратились к фрилансерам, значит штатного программиста либо нет, либо он не справился с поставленной задачей. Поэтому ценник вполне адекватен.

21.01.2011 15:48:18
#17 demongloom

Выше, приведено решение которое решает только конкретную задачу, не буду судить плохо оно или хорошо. Но часто бывает необходимо оперировать массивами в виде рекордсета, где каждый элемент массива «строка» сам является массивом - «колонки» с данными. Естественно нужно иногда сортировать по нескольким полям сразу.
Для этого можно воспользоваться array_multisort.

В комментариях на http://php.net/manual/en/function.array-multisort.php есть примеры использования этой функции для сортировки рекордсетов. Между версиями 5.2 и 5.3 есть разница, так что обратить на это внимание.

21.01.2011 21:54:13

Спасибо за скрипт, не ожидал найти... Удачи в работе и жизни!

airsound

23.01.2011 06:06:54

«За решение этой задачи у моего знакомого фрилансеры попросили 4000 рублей. Как думаете, стоит оно того?»

Алексей, теперь я буду делать это за 200 рублей :D

4000 это слишком много. На эту сумму можно отличный дизайн заказать у тебя :)

24.01.2011 20:00:55

с удовольствием воспользовался приведённой выше ссылкой!

25.01.2011 12:09:59
#21 макс

ничего сложного, только этот алгоритм не оптимальный по количеству операций

сортировка с разделением хотя бы

26.01.2011 08:27:25

Если заплатили, значит стоит. Конечно работа не такая уж и пыльная, но если за это платят, значит стоит. К сожалению в нашем мире всегда так, за сложную работу -платят мало, а за протирание штанов - в основном больше. А алгоритмы и оптимизация доступны не каждому даже умному человеку, поэтому оно того стоит.

26.01.2011 11:49:32
#23 павел

давно программирую на php. могу сказать что с массивами работать на нем гораздо удобнее нежели на других языках.например на перл мне кажеться черт ногу сломит ))

26.01.2011 18:17:00
#24 joramix

Спасибо за скрипт

26.01.2011 18:41:31
#25 Garena

Спасибо, я это очень долго искал, и вдруг наткнулся у вас в блоге... Спасибо вам огромное еще раз! =)

27.01.2011 18:50:46
#26 FOUNDER

А зачем собственно эта сортировка используется? Я просто не понимаю малость видать. Если код настолько прост для написания, то наверняка 4к за него это многовато, хотя всякое бывает!

28.01.2011 06:38:57
#27 Торен

«За решение этой задачи у моего знакомого фрилансеры попросили 4000 рублей. Как думаете, стоит оно того?»
Цена уменьшается прямо пропорционально росту количества людей, знающих решение :)

28.01.2011 19:36:38
#28 Сергей

Так получилосб что у меня в одной БД несколько сайтов, как проще их разделить?

28.01.2011 23:44:50

Сергей, экспортировать нужные таблицы, а затем импортировать в другую БД. Всё очень просто.

29.01.2011 08:14:25
#30 Александр

Не хватает у меня сил на нормальное изучение php, предпочитаю все аутсорсить фрилансерам. Считаю что каждый должен делать только то, что умеет.

30.01.2011 22:32:52

Пробовал я себя в PHP. Ну не моё это. А почитаешь вас вроде и не сложно.
Думаю примерчик пригодиться.

31.01.2011 07:42:01
#32 Арсений

За скриптик спасибо, каждый должен заниматься тем, чем любит и умеет - это понятно, но даже человек, не имеющий отношения к программированию, может что-то с чем-то связать, ведь вас не программировать сложные структуры заставляют, а просто пораскинуть мозгами и поиском в гугле. %))

31.01.2011 09:36:41
#33 garant90

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

31.01.2011 15:16:26
#34 emchezgia

Не могу решиться учить php или нет, т.к. знакомый программист говорит, что при верстке сайта оно мне не поможет, что лучше javascript. Кто, что может посоветовать, стоит ли париться с php?

31.01.2011 22:48:32

Прикольно у вас тут. Без меня не скучаете? :-)

По поводу задачи.

1) то, что вы называете csv на самом деле csv не является. Учим матчасть: http://ru.wikipedia.org/wiki/CSV

2) если данные расположены в исходном файле именно так, как Вы указали, то решение будет таким:

$data = file(’database.csv’);
sort($data);
file_put_contents(’new_database.csv’, $data);

и не нужно городить велосипед ;-)

31.01.2011 22:56:01

fit-media.com, вы как всегда делаете поспешные неверные выводы :) А ещё называете себя программистом. Нужно вдумываться в задачу прежде, чем позориться перед молодёжью :)

Попробуйте перечитать.

31.01.2011 23:37:06

Never Lex,
т.е. вы хотите сказать, что результаты вашего и моего скриптов не одинаковые? ;)

ЗЫ
хинт, чтоб не разводить флейм: ключевая фраза в моем комменте была «если данные расположены в исходном файле именно так, как Вы указали»

ЗЗЫ
позориться - это учить молодежь написанию говнокода. )))

31.01.2011 23:46:45

fit-media.com, совершенно разные. При условии полной базы, а не выбранных для наглядности полей. Задачу можно понять, прочитав её. Если не помогает - перечитать. И так далее. А писать комментарии только потом, вместо того, чтобы наобум «блистать умом» :) А то ведь окажетесь в забавной ситуации сидя в луже.

Считаете себя умнее всех, а читать так и не научились.

03.02.2011 15:16:16
#39 Quadrocube

Never Lex,
Ууух, побежал регаться на фриланс-форумах) Задачка - олимпиада по программированию класса эдак 5-го (имеется ввиду Белорусская олимпиада, т.к. с Российскими не знаком). За это давать 4000? Просто смешно честно говоря)

П.с. Неверлекс, чего-то от тебя рассылки давно не видно, это ты не отсылал уже давно, или она до меня по каким-либо причинам просто не доходит?

06.02.2011 17:56:50
#40 Сатан

Дорого черезчур!
Слишком больше деньги, уж простите великодушно!

07.02.2011 14:59:24

Quadrocube, да, не отсылал. Всё будет :)

07.02.2011 16:30:40
#42 kewa

Спасибо за скрипт) типо такого как раз нужен был)

07.02.2011 19:00:01

Мой знакомый подобный скрипт писал за 20$. Мне кажется это борщ 4000 рублей

08.02.2011 01:16:57
#44 Валерий

Не, ну это дорого. А вообще интересно знать, сколько будут брать за 8 часов работы при 24 дневной занятости?

09.02.2011 20:05:30
#45 Oleg

с удовольствием воспользовался приведённой выше ссылкой!

10.02.2011 15:59:10

В какомто учебнике по php тоже встречал такое решение с использованием ф-й usort и strnatcmp

13.02.2011 14:51:09
#47 Valenok

Never Lex,
Да эта функция тут бы больше подошла, она бы не плохо упростила работу.
Согласитесь?

13.02.2011 15:13:27
#48 CelNet

Never Lex, соглашусь, она здесь самый раз!

13.02.2011 15:26:18

цена завышена оттого что все заказчики выбирают ПРО-шников, забывая о начинающих программистах, которые как раз таки и решили бы эту задачу за 200р. ну или за 300р. :)

16.02.2011 21:47:32

Valenok, CelNet, жду от вас решения с помощью array_walk и доказательством упрощения :)

17.02.2011 01:30:20

На счет уппрощения...

Если перестать ёрничать на счет исходных форматов и прочей фигни, то более шустрым решением будет примерно такое (комментарии выкинул - и так все понятно):

<?php
$data = file(’database.csv’);

for($i=0, $c=count($data); $i<$c; $i++)
{
$a = explode(’|’, $data[$i]);
$database[] = array($a[3].’ ’.$a[4].’ ’.$a[5], $data[$i]);
}

usort($database, ’cmp’);

$new_data = ’’;
for($i=0; $i<$c; $i++)
$new_data .= $data[$i][1];

// запись в файл
file_put_contents(’new_database.csv’, $new_data);

function cmp($a, $b) { return strnatcmp($a[0], $b[0]); }
?>

17.02.2011 06:54:41

fit-media.com, забавно. Почему этот вариант проще и быстрее? Пробовали тестировать? Не работает.

17.02.2011 10:46:28

Быстрее, потому, что содержит в разы меньше вызовов функций и ветвлений, т.е. самых «прожорливых» в плане скорости операций . Хотите убедиться - создайте файл с миллионом строк и прогоните его через оба скрипта.

Не работает.

Естественно не работает, т.к. писался прямо в комментарии форума и ни разу не запускался вживую. Имя переменной перепутано. Вместо $new_data .= $data[$i][1]; должно быть $new_data .= $database[$i][1];

Неужели трудно было заметить эту опечатку?

ЗЫ
Работает прекрасно даже с данными в UTF-8.

ЗЗЫ
Добавьте в редактор комментариев ББ-тэг для вставки кода, будет удобнее.

17.02.2011 11:07:34

fit-media.com, сейчас нет времени смотреть всё, что присылают. В этой версии движка ББ-тег добавлять не буду. В следующей обязательно.

23.02.2011 15:56:34

Ппц я в пхп ваще не понимаю, я ток выучил ксс и аштиэмель

08.03.2011 14:24:53
#56 Sibluder

Обычно когда я пишу какой-то скрипт или программу, я не лезу в Google за исходниками, а пытаюсь сам написать программу(скрипт). Потом уже лезу в Google и сравниваю свой исходник с уже готовыми.

10.03.2011 10:14:57
#57 Lex

Sibluder, на мой взгляд так и следует делать, так сказать учиться самим у себя.

18.03.2011 20:52:36
#58 karanic

Sibluder, но не всегда же есть такая куча времени, чтобы успеть сделать, потом найти, а потом еще и спокойно сверить на качество.

20.03.2011 13:32:39

karanic,
Совершенно верно, еще же нужно анализировать.

20.03.2011 22:57:56

Возможно пригодится. Возьму на заметку.

22.03.2011 20:46:51
#61 mccats

Согласна, если есть спрос, то и цена такой работе должна быть соотвотственная. Кому-то, чтоб заработать эти деньги пришлось бы попотеть.

13.04.2011 21:16:22
#62 Vasya

4000? За что!?

04.05.2011 19:25:55
#63 socpiter

Я раньше в делфы это делал, так что мне это и в ПХП сделать будет не трудно.

19.05.2011 20:54:04
#64 Дмитрий

Знание знание знание =)

11.06.2011 14:22:03
#65 Вячеслав

Я недавно начал изучать PHP потому что идей много и денег не так много )) Своими силами сложнее, но потом экономия. Спасибо за статью.. пришлось правда въезжать немного...

27.10.2011 10:19:39

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

13.12.2011 09:44:04

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

23.12.2011 15:56:55

Never Lex,
Я перечитал 20 раз, мысль посетила такая же. Либо вы не умеете ставить задачи, либо вы не понимаете сути сортировки

23.12.2011 15:59:15

Макс, «такая же» это какая? :)

21.03.2013 21:36:37

НЕКРОПОСТ!!

Берут 4к, чтобы такую херню не писали =)
А что если csv у тебя на 500мб?
Твой скрипт упадет в allowed size memory
Памяти хватит,целиком файл читать?)

22.03.2013 05:07:22

Dqqqqqqq, конечно скрипт не для больших файлов)

28.12.2013 11:04:33

отличное решение на основе встроенной функции, в духе php. что мешает хранить данные в *sql базе?

Оставьте комментарий [форматирование]

Пожалуйста, воздержитесь от спама и идиотских высказываний. Жёсткая модерация. Ссылки закрыты атрибутом nofollow, а значит не несут пользы для продвижения!
Ссылки на всё кроме личных блогов и тематических блогов, сходных по тематике с данным, вырезаются.



Мой RSS фид