@popov654
Специалист в области веб-технологий

Не работает usort?

Есть следующий код. Он задуман так: получаем JSON со стороннего сервера (тот сервер получает данные с другого сервера, поскольку напрямую соединение не получалось установить с IP хостера), но этот JSON не совсем оптимально отсортирован. Цель - сделать сортировку по релевантности. Релевантность считаю как новый элемент массива с индексом 5, возможные значения - от 0 до 1, вещественное число.

По идее, всё должно сортироваться как надо, но на выходе получается полный бред. Массив выглядит так, как будто он и вовсе не сортировался. Хотя если в функцию сравнения поставить отладочный вывод - видно, что код вроде как исполняется.

Что я делаю не так?

<?php
   $search = $_GET['search'];
   
   $url = "http://popov654.pp.ru/mp3.php?search=".(preg_match("/Chrome/", $_SERVER['HTTP_USER_AGENT']) ? urlencode(iconv('cp1251', 'UTF-8', $_GET['search'])) : urlencode($_GET['search']));
   if (isset($_GET['page']) && (int)$_GET['page'] > 0) $url .= "&page=".(int)$_GET['page'];
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($ch, CURLOPT_HEADER, 0);

   $output = mb_convert_encoding(curl_exec($ch), 'CP1251', 'UTF-8');
   curl_close($ch);

   $template = '|<div class="x-track" data-mp3id="([0-9]+)" data-artist="([^"]+)" data-name="([^"]+)" >\\s*<a href="javascript:" class="x-icons x-play x-icon-play" title="[^"]+">&nbsp;</a>\\s*<a href="javascript:" style="display: none;" class="x-icons x-pause x-icon-pause" title="[^"]+">&nbsp;</a>\\s*<strong><a href="[^"]+" title="[^"]+">[^>]+</a></strong> -  <a href="[^"]+" title="[^"]+">[^>]+</a>  \\(([0-9]+:[0-9]{2})\\)|';
   preg_match_all($template, $output, $matches, PREG_SET_ORDER);

   preg_match_all('|<a href="./search/[^?]+\\?p=[0-9]+">([0-9]+)</a>|', $output, $a, PREG_SET_ORDER);
   $page_count = count($a) > 0 ? $a[count($a)-1][1] : 1;

   $words = explode(" ", $_GET['search']);

   function reorder(&$m) {
      global $words;
      for ($i = 0; $i < count($m); $i++) {
         if (preg_match('/^'.$_GET['search'].'(\\s|$)/', $m[$i][2]) || preg_match('/^'.$_GET['search'].'(\\s|$)/', $m[$i][3])) $m[$i][5] = 1;
         else if (preg_match('/\\s'.$_GET['search'].'(\\s|$)/', $m[$i][2]) || preg_match('/\\s'.$_GET['search'].'(\\s|$)/', $m[$i][3])) $m[$i][5] = 0.8;

         else {
            for ($j = 0; $j < count($words); $j++) {
               if (preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][2]) && preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][3])) {
                  $m[$i][5] = 0.7;
                  break;
               }
               if (preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][2]) || preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][3])) {
                  $m[$i][5] = 0.6;
                  break;
               }
            }
         }

         if (!isset($m[$i][5])) $m[$i][5] = 0.4;
      }

      usort($m, function($a, $b) {
         return (float)$a[5]-(float)$b[5];
      });
   }

   reorder($matches);
   //print_r($matches);
   $result = '';
   for ($i = 0; $i < count($matches); $i++) {
      if ($result != '') $result .= ', ';
      $result .= '{"artist":"'.$matches[$i][2].'", "title":"'.str_replace('"', '\\"', $matches[$i][3]).'", "time":"'.$matches[$i][4].'", "url":"http://mixpromo.net/getsong/'.$matches[$i][1].'"}';
   }
   echo '{ "pages": '.$page_count.', "items": ['.$result.'] }';

?>
  • Вопрос задан
  • 472 просмотра
Решения вопроса 1
@popov654 Автор вопроса
Специалист в области веб-технологий
Чтобы не путать читателей, да и справедливости ради, привожу верный код ниже.

Ошибка была в том, что нельзя возвращать из функции сортировки значения, отличные от 0, 1 или -1 (как минимум в PHP 5.3).

Спасибо Andrzej Wielski за подсказку :)

<?php
   $search = $_GET['search'];
   
   $url = "http://popov654.pp.ru/mp3.php?search=".(preg_match("/Chrome/", $_SERVER['HTTP_USER_AGENT']) ? urlencode(iconv('cp1251', 'UTF-8', $_GET['search'])) : urlencode($_GET['search']));
   if (isset($_GET['page']) && (int)$_GET['page'] > 0) $url .= "&page=".(int)$_GET['page'];
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($ch, CURLOPT_HEADER, 0);

   $output = mb_convert_encoding(curl_exec($ch), 'CP1251', 'UTF-8');
   curl_close($ch);

   $template = '|<div class="x-track" data-mp3id="([0-9]+)" data-artist="([^"]+)" data-name="([^"]+)" >\\s*<a href="javascript:" class="x-icons x-play x-icon-play" title="[^"]+">&nbsp;</a>\\s*<a href="javascript:" style="display: none;" class="x-icons x-pause x-icon-pause" title="[^"]+">&nbsp;</a>\\s*<strong><a href="[^"]+" title="[^"]+">[^>]+</a></strong> -  <a href="[^"]+" title="[^"]+">[^>]+</a>  \\(([0-9]+:[0-9]{2})\\)|';
   preg_match_all($template, $output, $matches, PREG_SET_ORDER);

   preg_match_all('|<a href="./search/[^?]+\\?p=[0-9]+">([0-9]+)</a>|', $output, $a, PREG_SET_ORDER);
   $page_count = count($a) > 0 ? $a[count($a)-1][1] : 1;

   $words = explode(" ", $_GET['search']);

   function reorder(&$m) {
      global $words;
      for ($i = 0; $i < count($m); $i++) {
         if (preg_match('/^'.$_GET['search'].'(\\s|$)/', $m[$i][2]) || preg_match('/^'.$_GET['search'].'(\\s|$)/', $m[$i][3])) $m[$i][5] = 1;
         else if (preg_match('/\\s'.$_GET['search'].'(\\s|$)/', $m[$i][2]) || preg_match('/\\s'.$_GET['search'].'(\\s|$)/', $m[$i][3])) $m[$i][5] = 0.8;

         else {
            for ($j = 0; $j < count($words); $j++) {
               if (preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][2]) && preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][3])) {
                  $m[$i][5] = 0.7;
                  break;
               }
               if (preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][2]) || preg_match('/(^|\\s)'.$words[$j].'(\\s|$)/', $m[$i][3])) {
                  $m[$i][5] = 0.6;
                  break;
               }
            }
         }

         if (!isset($m[$i][5])) $m[$i][5] = 0.4;
      }

      usort($m, usort($m, function($a, $b) {
         if ($a[5] == $b[5]) return 0;
         return ($a[5] > $b[5]) ? -1 : 1;
      });
   }

   reorder($matches);
   $result = '';
   for ($i = 0; $i < count($matches); $i++) {
      if ($result != '') $result .= ', ';
      $result .= '{"artist":"'.$matches[$i][2].'", "title":"'.str_replace('"', '\\"', $matches[$i][3]).'", "time":"'.$matches[$i][4].'", "url":"http://mixpromo.net/getsong/'.$matches[$i][1].'"}';
   }
   echo '{ "pages": '.$page_count.', "items": ['.$result.'] }';

?>
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
wielski
@wielski
✔ Совет: Вам помогли? Отметьте ответы решением.
В вашей функции reorder входящие данные - переменная $matches
Но, увы и ах, функция ничего не возвращает.
Исходя из этого, выполняя функцию reorder вы добиваетесь ровным счетом ничего.

И не надо пожалуйста спорить со мной о том что код правильный и все так и должно быть, проходили. Просто послушайтесь совета - добавьте return $m в функцию, и записывайте результат работы функции в переменную.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы