За последние 24 часа нас посетили 38590 программистов и 8127 роботов. Сейчас ищут 1736 программистов ...

Сортировка массива по положению слова в фразе

Тема в разделе "PHP для новичков", создана пользователем Moor, 14 ноя 2022.

  1. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    Нетривиальная (для меня) задачка попалась, ребята, прошу помощи.

    Имеем массив из фраз, например, такой:
    1. Пятнадцатилетний капитан
    2. Капитан Фракасс
    3. Капитанская дочка
    4. Первый и последний Капитан
    Задача: пересортировать массив так, чтобы первыми стояли фразы, где слово целое "капитан" как можно ближе к началу фразы. На выходе надо получить так:
    1. Капитан Фракасс
    2. Пятнадцатилетний капитан
    3. Первый и последний Капитан
    4. Капитанская дочка
    Может, кто-то писал что-то похожее?
     
  2. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.874
    Симпатии:
    753
    Адрес:
    Татарстан
    Пишете свою функцию, которая:для любой входной фразы, выдает индекс нахождения слова в ней:
    - для этого входную фразу разбиваете на слова
    - находите индекс искомого слова, если слово не найдено то возвращаем например null или false
    применяете функцию uasort() сортировки с данной функцией

    показывайте код что у вас - подскажем
     
    Moor и don.bidon нравится это.
  3. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    @ADSoft , спасибо за идею эксплодить фразы в массивы, это именно то, что требуется. Я перечитал свой пост и понял, что задачу описал не вполне верно – фразы могут быть неуникальны, но у них есть уникальные айдишники. Из-за того, что нужно сохранять и то, и другое, да еще и индекс слова, я не осилил, как применить uasort() и породил вот такого монстра:
    PHP:
    1. <?php
    2.  
    3. $my_titles = array(
    4.     5486 => 'Пятнадцатилетний капитан',
    5.     8476 => 'Шестнадцатилетний капитан',
    6.     1247 => 'Шестнадцатилетний капитан',
    7.     9548 => 'Капитан Фракасс',
    8.     7854 => 'Капитанская дочка',
    9.     8888 => 'Капитан. Странная история',
    10.     7755 => 'Первый и последний Капитан',
    11.     6999 => 'Клуб знаменитых капитанов'
    12. );
    13. $my_word = 'капитан';
    14.  
    15. function sort_by_word_place ($titles, $word) {
    16.     // $titles – array ['id'] => 'title'
    17.     // $word – search string
    18.  
    19.     $titles_true = array();
    20.     $titles_false = array();
    21.     $all_titles = array();
    22.     $count = 0;
    23.     foreach ($titles as $title_k => $title_v) {
    24.         $title = preg_replace("/(?![-])\p{P}/u", " ", $title_v);
    25.      
    26.         $title_arr = array();
    27.         $title_arr = explode(' ', mb_strtolower($title));
    28.         if (in_array($word, $title_arr)) {
    29.             $key = array_search($word, $title_arr);
    30.             $titles_true[$title_k]['index'] = $key;
    31.             $titles_true[$title_k]['title'] = $title_v;
    32.             $count++;
    33.         } else {
    34.             $titles_false[$title_k] = $title_v;
    35.         }
    36.     }
    37.  
    38.     $titles_true_sorted = array();
    39.     $index = 0;
    40.     for ($i = 0; $i < count($titles_true); ++$i) {
    41.         foreach ($titles_true as $titles_true_k => $titles_true_v) {
    42.             if ($titles_true_v['index'] == $index) {
    43.                 $titles_true_sorted[$titles_true_k] = $titles_true_v['title'];
    44.             }
    45.         }
    46.         $index++;
    47.     }
    48.  
    49.     return array_merge($titles_true_sorted, $titles_false);
    50. }
    51.  
    52. print_r(sort_by_word_place($my_titles, $my_word));
    53.  
    54. // OUTPUT
    55.     0 => 'Капитан Фракасс',
    56.     1 => 'Капитан. Странная история',
    57.     2 => 'Пятнадцатилетний капитан',
    58.     3 => 'Шестнадцатилетний капитан',
    59.     4 => 'Шестнадцатилетний капитан',
    60.     5 => 'Первый и последний Капитан',
    61.     6 => 'Капитанская дочка',
    62.     7 => 'Клуб знаменитых капитанов'
    63. );
    Чую, что это получилось избыточно тяжеловесным, буду признателен за подсказки по оптимизации.
     
  4. Moor

    Moor Новичок

    С нами с:
    1 мар 2020
    Сообщения:
    23
    Симпатии:
    0
    Адрес:
    Latvia
    UPD. Ну и я только что допёр, что это всё работает только в том случае, если искать нужно 1 слово, а не фразу.
     
  5. Drunkenmunky

    Drunkenmunky Старожил

    С нами с:
    12 авг 2020
    Сообщения:
    1.511
    Симпатии:
    284
    PHP:
    1. <pre>
    2. <?php
    3. $my_titles = array( // UTF-8
    4.     5486 => 'Пятнадцатилетний капитан',
    5.     8476 => 'Шестнадцатилетний капитан',
    6.     1247 => 'Шестнадцатилетний капитан',
    7.     9548 => 'Капитан Фракасс',
    8.     7854 => 'Капитанская дочка',
    9.     8888 => 'Капитан. Странная история',
    10.     7755 => 'Первый и последний Капитан',
    11.     6999 => 'Клуб знаменитых капитанов'
    12. );
    13.  
    14. $offsets = array();
    15.  
    16. foreach ($my_titles as $key => $value)
    17. {
    18.       preg_match('/\bкапитан\b/iu', $value.' ', $matches, PREG_OFFSET_CAPTURE);
    19.       $offsets[$key] = isset($matches[0][1]) ? $matches[0][1] : strlen($value);
    20. }
    21.  
    22. //print_r ($offsets);
    23.  
    24. asort($offsets);
    25. //print_r ($offsets);
    26.  
    27. $new_titles = array();
    28.  
    29. foreach ($offsets as $key => $value)
    30. {
    31.     $new_titles[$key] =  $my_titles[$key];
    32. }
    33.  
    34. print_r ($my_titles);
    35. print_r ($new_titles);
    36. ?>