Нетривиальная (для меня) задачка попалась, ребята, прошу помощи. Имеем массив из фраз, например, такой: Пятнадцатилетний капитан Капитан Фракасс Капитанская дочка Первый и последний Капитан Задача: пересортировать массив так, чтобы первыми стояли фразы, где слово целое "капитан" как можно ближе к началу фразы. На выходе надо получить так: Капитан Фракасс Пятнадцатилетний капитан Первый и последний Капитан Капитанская дочка Может, кто-то писал что-то похожее?
Пишете свою функцию, которая:для любой входной фразы, выдает индекс нахождения слова в ней: - для этого входную фразу разбиваете на слова - находите индекс искомого слова, если слово не найдено то возвращаем например null или false применяете функцию uasort() сортировки с данной функцией показывайте код что у вас - подскажем
@ADSoft , спасибо за идею эксплодить фразы в массивы, это именно то, что требуется. Я перечитал свой пост и понял, что задачу описал не вполне верно – фразы могут быть неуникальны, но у них есть уникальные айдишники. Из-за того, что нужно сохранять и то, и другое, да еще и индекс слова, я не осилил, как применить uasort() и породил вот такого монстра: PHP: <?php $my_titles = array( 5486 => 'Пятнадцатилетний капитан', 8476 => 'Шестнадцатилетний капитан', 1247 => 'Шестнадцатилетний капитан', 9548 => 'Капитан Фракасс', 7854 => 'Капитанская дочка', 8888 => 'Капитан. Странная история', 7755 => 'Первый и последний Капитан', 6999 => 'Клуб знаменитых капитанов' ); $my_word = 'капитан'; function sort_by_word_place ($titles, $word) { // $titles – array ['id'] => 'title' // $word – search string $titles_true = array(); $titles_false = array(); $all_titles = array(); $count = 0; foreach ($titles as $title_k => $title_v) { $title = preg_replace("/(?![-])\p{P}/u", " ", $title_v); $title_arr = array(); $title_arr = explode(' ', mb_strtolower($title)); if (in_array($word, $title_arr)) { $key = array_search($word, $title_arr); $titles_true[$title_k]['index'] = $key; $titles_true[$title_k]['title'] = $title_v; $count++; } else { $titles_false[$title_k] = $title_v; } } $titles_true_sorted = array(); $index = 0; for ($i = 0; $i < count($titles_true); ++$i) { foreach ($titles_true as $titles_true_k => $titles_true_v) { if ($titles_true_v['index'] == $index) { $titles_true_sorted[$titles_true_k] = $titles_true_v['title']; } } $index++; } return array_merge($titles_true_sorted, $titles_false); } print_r(sort_by_word_place($my_titles, $my_word)); // OUTPUT array ( 0 => 'Капитан Фракасс', 1 => 'Капитан. Странная история', 2 => 'Пятнадцатилетний капитан', 3 => 'Шестнадцатилетний капитан', 4 => 'Шестнадцатилетний капитан', 5 => 'Первый и последний Капитан', 6 => 'Капитанская дочка', 7 => 'Клуб знаменитых капитанов' ); Чую, что это получилось избыточно тяжеловесным, буду признателен за подсказки по оптимизации.
UPD. Ну и я только что допёр, что это всё работает только в том случае, если искать нужно 1 слово, а не фразу.
PHP: <pre> <?php $my_titles = array( // UTF-8 5486 => 'Пятнадцатилетний капитан', 8476 => 'Шестнадцатилетний капитан', 1247 => 'Шестнадцатилетний капитан', 9548 => 'Капитан Фракасс', 7854 => 'Капитанская дочка', 8888 => 'Капитан. Странная история', 7755 => 'Первый и последний Капитан', 6999 => 'Клуб знаменитых капитанов' ); $offsets = array(); foreach ($my_titles as $key => $value) { preg_match('/\bкапитан\b/iu', $value.' ', $matches, PREG_OFFSET_CAPTURE); $offsets[$key] = isset($matches[0][1]) ? $matches[0][1] : strlen($value); } //print_r ($offsets); asort($offsets); //print_r ($offsets); $new_titles = array(); foreach ($offsets as $key => $value) { $new_titles[$key] = $my_titles[$key]; } print_r ($my_titles); print_r ($new_titles); ?>