За последние 24 часа нас посетил 9271 программист и 461 робот. Сейчас ищут 104 программиста ...

Алгоритмы & Полезности

Тема в разделе "Решения, алгоритмы", создана пользователем Chushkin, 4 авг 2015.

  1. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    Catrina пыталась создать подобную тему, но там всё скатилось в трёп, - это "попытка 2". Гуру, присоединяйтесь.
    Начну с пары простейших примочек...

    1) Аналог trim() для unicode - удаляет все пробельные символы в начале и в конце.
    Код (PHP):
    1. preg_replace('/^\s+|\s+$/u', '', $text) 
    2) Swap - меняет значения переменных местами.
    Код (PHP):
    1.      function Swap(&$p1, &$p2) {
    2.         $tmp = $p1;
    3.         $p1 = $p2;
    4.         $p2 = $tmp;
    5.     }
    6.  
    3) LastKey - возвращает ключ последнего элемента массива.
    Код (PHP):
    1.     function LastKey(array $a) {
    2.         end($a);
    3.         return key($a);
    4.     } 
     
    denis01 нравится это.
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.329
    Симпатии:
    1.034
    Адрес:
    там-сям
    Тема хорошая. Замечу только, что обычный Трим вполне мультибайтно-безопасный.
    http://stackoverflow.com/a/10067670/272885

    Добавлено спустя 32 минуты 48 секунд:
    Полезные кейсы оператора "+" с массивами:

    Значения по умолчанию:
    Код (PHP):
    1. $defaults = ['host' => 'localhost', 'user' => 'root', 'password' => ''];
    2. var_dump($array + $defaults);
    Значения по умолчанию
    и при этом оставить только те ключи массива, которые упоминаются в дефолтовом массиве:
    Код (PHP):
    1. $defaults = ['host' => 'localhost', 'user' => 'root', 'password' => ''];
    2. var_dump(array_intersect_key($array, $defaults) + $defaults);
    Сравнение нескольких "полей" сразу:
    Код (PHP):
    1. $condition = ['name' => 'John', 'city' => 'New York'];
    2. If ($condition + $array == $array) echo 'Ok';
     
    twim32, Sergey108 и denis01 нравится это.
  3. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    Да, очень удобная. Я часто пользуюсь подобной конструкцией для назначения default-значений.
    Что-то типа:
    Код (PHP):
    1. function F($param, $options=[]) {
    2.   $options += ['option1'=>value1, 'option2'=>value2, ...]
    3.   // т.е. option1 всегда будет, или назначен или по умолчанию. 
    4.   ...
    5. } 
     
    denis01 нравится это.
  4. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    если нужно выкинуть из массива все пустые строки с нулями
    Код (PHP):
    1. print_r( array_filter( ['',0,1,'2','a'] ) ); // 1,2,a  
     
    denis01 нравится это.
  5. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    Дополню runcore.

    4) array_filter
    а) Удалить из массива элементы только со значением NULL.
    Код (PHP):
    1. array_filter($array, function($v) { return $v !== null; } ) 
    б) Удалить из массива элементы только со значениями NULL и пустая строка (в т.ч. состоящая из одних пробелов).
    Код (PHP):
    1. array_filter($array, function($v) { return $v !== null and trim($v) !== ''; } ) 
     
    denis01 нравится это.
  6. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    5) Заменить слово, содержащие кусок текста.
    Код (PHP):
    1. preg_replace('/(\b\w*текст\w*\b)/ui', '#', $source) 
    Пример из другого топика другого форума:
    Код (PHP):
    1. $s = 'Вот приехал сосед из соседней деревни пососедству';
    2. var_dump(htmlentities(preg_replace('/(\b\w*сосед\w*\b)/ui', '<b>$1</b>', $s)));
    3. // "Вот приехал <b>сосед</b> из <b>соседней</b> деревни <b>пососедству</b>"     
     
    Abyss и denis01 нравится это.
  7. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    6) Сравнить два JSON,ARRAY значения по ключам.
    Код (PHP):
    1. /**
    2.  * Сравнивает два JSON, ARRAY значения по ключам.
    3.  * @param array|string $j1 ARRAY или JSON данные.
    4.  * @param array|string $j2 ARRAY или JSON данные.
    5.  * @return bool TRUE - равны, FALSE - не равны.
    6.  */
    7. function EqualRecursive($j1, $j2) {
    8.     if(is_string($j1)) {
    9.         $j1 = json_decode($j1, true);
    10.     }
    11.     if(is_string($j2)) {
    12.         $j2 = json_decode($j2, true);
    13.     }
    14.     $equal = (count($j1) == count($j2) and !array_diff_key($j1, $j2));
    15.     if($equal) {
    16.         foreach($j1 as $k=>$j) {
    17.             if(is_array($j)) {
    18.                 $equal = KeysEqualRecursive($j, $j2[$k]);
    19.                 if(!$equal) break;
    20.             }
    21.         }
    22.     }
    23.     return $equal;
    24. } 
    Тест:
    Код (PHP):
    1. var_dump( EqualRecursive('{"index": 0, "tags": ["abc"]}', '{"index": 1, "tags": ["xyz"]}')); // equal
    2. var_dump( EqualRecursive('{"tags": ["abc","def"], "index": 0}', '{"index": 1, "tags": ["xyz"]}')); // not equal
    3. var_dump( EqualRecursive('{"tags": ["abc"], "index": 0, "хрень": 0}', '{"index": 1, "tags": ["xyz"]}')); // not equal
    4. var_dump( EqualRecursive(["tags"=> ["abc"], "index"=> 0], ["index"=> 1, "tags"=> ["xyz"]])); // equal
    5. var_dump( EqualRecursive(["tags"=> ["abc"], "index"=> 0, "хрень"=> 0], ["index"=> 1, "tags"=> ["xyz"]])); // not equal
     
    denis01 нравится это.
  8. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    7) Получить все числа разделённые пробелами из текста:
    Код (PHP):
    1. preg_match_all('/(\d+\s*)+(?<!\D)/', $text, $out);
    Тест:
    Код (PHP):
    1. $text = 'Сумма 4 748 730 была получена из суммы 67 839 умноженной на коэффициент K = 70';
    2. preg_match_all('/(\d+\s*)+(?<!\D)/', $text, $out);
    3. var_dump($out[0]);
     
    denis01 нравится это.
  9. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    8) Аналог trim() для unicode - удаляет все пробельные символы в начале и в конце:
    Код (PHP):
    1. preg_replace('/^\s+|\s+$/u', '', $text) 
     
    denis01 нравится это.
  10. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.450
    Симпатии:
    582
    День сурка
     
    denis01 нравится это.
  11. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    9) Заменить N-ое вхождение части строки.
    Например, заменить третью двойку на "0" и четвёртый символ "b" на "B":
    Код (PHP):
    1. $s = 'бе бе 123 123 123 123 abc abc abc abc';
    2. var_dump(preg_replace(['/(.*2.*2.*)(2)/U', '/(.*b.*b.*b.*)(b)/U'], ['${1}0', '${1}B'], $s));
    3. // результат: string(41) "бе бе 123 123 103 123 abc abc abc aBc"
     
    denis01 нравится это.
  12. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    10) Поменять соседние символы строки местами.
    Например, “Hello World!” -> “eHll ooWlr!d”:
    PHP:
    1. $s = 'Hello World!';
    2. var_dump(preg_replace('/(.)(.)/u', '$2$1' $s));
     
    denis01 нравится это.
  13. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    11) Заключить текст между разделителями в HTML-теги
    Код (PHP):
    1. $text= '
    2. Часть 1
    3. ----------------------------------------------------------------------
    4. Некий текст
    5. до следующего разделителя
    6. ----------------------------------------------------------------------
    7.  
    8. Часть 2
    9. ----------------------------------------------------------------------
    10. Текст
    11. ----------------------------------------------------------------------
    12. Прочая хрень...
    13. ';
    14.  
    15. //Например, разделитель это 65 или более тире подряд с горизонтальными пробелами до:
    16. $resultat1 = preg_replace('/((?:\h*\-{65,})(?:.*?)(?:\-{65,}))/us', "<pre>\n$1\n</pre>", $text);
    17. // п.с. (?:) использовано для наглядности
    18.  
    19. // Более сложный вариант: разделить текст на три части, - первый разделитель, текст между
    20. // разделителями, второй разделитель. Перед первым разделителем открыть тег PRE, после
    21. // второго закрыть, текст заключить в тег B. Разделитель это 65 или более тире подряд с
    22. // горизонтальными пробелами до и после.
    23. $resultat2 = preg_replace('/(\h*\-{65,}\h*)(.*?)(\h*\-{65,}\h*)/us', "<pre>\n$1\n<b>$2</b>\n$3\n</pre>", $text);
    Результат 1:
    Код (Text):
    1.  
    2. string(479) "
    3. Часть 1
    4. <pre>
    5. ----------------------------------------------------------------------
    6. Некий текст
    7. до следующего разделителя
    8. ----------------------------------------------------------------------
    9. </pre>
    10.  
    11. Часть 2
    12. <pre>
    13. ----------------------------------------------------------------------
    14. Текст
    15. ----------------------------------------------------------------------
    16. </pre>
    17. Прочая хрень...
    18. "
    Результат 2:
    Код (Text):
    1.  
    2. string(521) "
    3. Часть 1
    4. <pre>
    5. ----------------------------------------------------------------------
    6. <b>
    7. Некий текст
    8. до следующего разделителя
    9. </b>
    10. ----------------------------------------------------------------------
    11. </pre>
    12.  
    13. Часть 2
    14. <pre>
    15. ----------------------------------------------------------------------
    16. <b>
    17. Текст
    18. </b>
    19. ----------------------------------------------------------------------
    20. </pre>
    21. Прочая хрень...
    22. "
     
    #13 Chushkin, 29 июл 2016
    Последнее редактирование: 29 июл 2016
    denis01 нравится это.
  14. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.329
    Симпатии:
    1.034
    Адрес:
    там-сям
    Как увеличить время (таймстамп) на один день
    внезапно!

    Казалось бы, прибавляй 24 * 60 * 60 и радуйся. Это так, если не знать про смену времени зима/лето, которая происходит в половине стран или провинций стран. При наступлении даты Д мы получим время на час меньше или больше, чем хотелось (в текстовом представлении конечно).

    Безопасный и элегантный способ:
    1. установить текущий часовой пояс в начале работы, типа
    Код (Text):
    1. date_default_timezone_set('Australia/Melbourne');
    2. прибавлять или отнимать через функцию strtotime. здесь строкой является только "команда", второй аргумент это таймстамп и на выходе тоже таймстамп.
    Код (Text):
    1. $next = strtotime('+1 day', $current);
    в зависимости от контекста здесь происходит увеличение на 23, 24 или 25 часов. date('Y-m-d H:i:s', $next) будет всегда тот, что мы ожидали увидеть.
     
    machetero и denis01 нравится это.
  15. iliavlad

    iliavlad Активный пользователь

    С нами с:
    24 янв 2009
    Сообщения:
    1.689
    Симпатии:
    4
    а есть пример применения этого дела? много раз видел подобную задачу, но на практике как-то не сталкивался.
     
  16. denis01

    denis01 Суперстар
    Команда форума Модератор

    С нами с:
    9 дек 2014
    Сообщения:
    12.245
    Симпатии:
    1.708
    Адрес:
    Молдова, г.Кишинёв
    @iliavlad сортировка, может пузырёк или другой, частично поиск большего или меньшего
     
  17. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
  18. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    13) Получить записи с чётными и нечётными ключами, для значений больше нуля.

    Вариант без сохранения ключей:
    PHP:
    1. $data = [2,1,2,3,5,7,9,11,4,0,0];
    2. $odd = array_column(array_chunk(array_filter($data), 2), 1);
    3. $even = array_column(array_chunk(array_filter($data), 2), 0);
    Вариант с сохранением ключей:
    PHP:
    1. $data = [2,1,2,3,5,7,9,11,4,0,0];
    2. $odd  = array_filter($data, function($v, $k) { return ($k % 2 and $v > 0); }, ARRAY_FILTER_USE_BOTH);
    3. $even = array_filter($data, function($v, $k) { return (!($k % 2) and $v > 0); }, ARRAY_FILTER_USE_BOTH);
    Вариант с сохранением ключей без использования функций:
    PHP:
    1.    
    2. $data = [2,1,2,3,5,7,9,11,4,0,0];
    3. $odd = [];
    4. $even = [];
    5. foreach($data as $k=>$v) {
    6.     if(!($k % 2) and $v > 0) {
    7.         $even[$k] = $v;
    8.     } elseif($k % 2 and $v > 0) {
    9.         $odd[$k] = $v;
    10.     }    
    11. }
     
    Anhk и igordata нравится это.
  19. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.761
    Адрес:
    :сердА
    14) Понижение n-мерности массивов.

    array_undimention(array $array[,int $final_deep = 1])
    Приводит N-мерный массив с однородной структурой к количеству измерений, указанному в $final_deep.

    Передаваемые параметры:
    array $array
    Массив, который требуется обработать.
    int $final_deep = 1
    Необязательный параметр. Количество измерений, к которым нужно привести $array. По умолчанию равен 1.

    Возвращаемые значения:
    ($final_deep)-мерная версия массива $array, либо false в случае, если $array не является массивом, и/или $final_deep<1.

    Замечания:
    При снижении мерности массивов, ключи измерения N отбрасываются, а их значения смерживаются в одно единое измерение.
    Таким образом, к примеру, при сведении какого-либо массива к 1-мерному, он будет представлять собой список значений,
    которые имели максимальный индекс вложенности.

    Передаваемый массив должен иметь однородную структуру. То есть, любая ячейка должна иметь ту же иерархию элементов,
    что и начальная. Количество вложенных элементов у разных ячеек значения не играет. Важно лишь единство структуры.

    Структура массива определяется по первой ячейке.

    PHP:
    1. function array_undimention($array, $final_deep = 1)
    2. {
    3.     if ((is_array($array)) && ($final_deep >= 1)) {
    4.         $temp = current($array);
    5.         $real_deep = 1;
    6.         while (is_array($temp)) {
    7.             $temp = current($temp);
    8.             $real_deep++;
    9.         }
    10.         if ($real_deep > $final_deep) {
    11.             $temp = [];
    12.             foreach ($array as $cell) {
    13.                 foreach ($cell as $sub_cell) {
    14.                     $temp[] = $sub_cell;
    15.                 }
    16.             }
    17.             $temp = array_undimention($temp, $final_deep);
    18.         } else {
    19.             $temp = $array;
    20.         }
    21.         return $temp;
    22.     }
    23.     return false;
    24. }
     
  20. Poznakomlus

    Poznakomlus Активный пользователь

    С нами с:
    12 сен 2014
    Сообщения:
    95
    Симпатии:
    19
    Адрес:
    Киев
    Решений есть масса без применения промежуточных переменных
    К примеру:
    PHP:
    1. $a = 5;
    2. $b = 10;
    3. $a = [$b, $b = $a][0];
    4. var_dump($a, $b); //10, 5
    @Fell-x27 Напиши, пример, на входе такой массив, нужно получить такой.
     
  21. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.419
    Симпатии:
    1.741
  22. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.761
    Адрес:
    :сердА
    Допустим, к нам пришел вот такой четырехмерный массив:

    PHP:
    1. $arr = [
    2.     "data1" => [
    3.         "cat1" => [
    4.             "val1" => [1, 2],
    5.             "val2" => [3, 4],
    6.             "val3" => [5, 6],
    7.             "val4" => [7, 8]
    8.         ],
    9.         "cat2" => [
    10.             "val1" => [10, 20],
    11.             "val2" => [40, 40],
    12.             "val3" => [50, 60],
    13.             "val4" => [70, 80]
    14.         ]
    15.     ],
    16.     "data2" => [
    17.         "cat1" => [
    18.             "val1" => [100, 200],
    19.             "val2" => [300, 400],
    20.             "val3" => [500, 600],
    21.             "val4" => [700, 800]
    22.         ],
    23.         "cat2" => [
    24.             "val1" => [1000, 2000],
    25.             "val2" => [3000, 4000],
    26.             "val3" => [5000, 6000],
    27.             "val4" => [7000, 8000]
    28.         ]
    29.     ]
    30. ];
    А нас интересует только содержимое последних массивов с числами, но так, чтобы они оставались массивами. То есть, нужно отсечь первые 2 измерения, чтобы остались только последние два.

    Код (Text):
    1. $new_arr = array_undimention($arr,2);
    Результатом будет такой массив:
    PHP:
    1. $new_arr = [
    2.     0 => [1, 2],
    3.     1 => [3, 4],
    4.     2 => [5, 6],
    5.     3 => [7, 8],
    6.     4 => [10, 20],
    7.     5 => [40, 40],
    8.     6 => [50, 60],
    9.     7 => [70, 80],
    10.     8 => [100, 200],
    11.     9 => [300, 400],
    12.     10 => [500, 600],
    13.     11 => [700, 800],
    14.     12 => [1000, 2000],
    15.     13 => [3000, 4000],
    16.     14 => [5000, 6000],
    17.     15 => [7000, 8000]
    18. ];
    Если же для $arr указать вторым параметром единицу, то получим просто одномерный массив
    PHP:
    1. $flat_arr = [1,2,3,4,5,6,7,8,10,20,30,40,50,60,70,80,100,200,300,400,500,600,700,800,900,1000,2000,3000,4000,5000,6000,7000,8000];
     
  23. Poznakomlus

    Poznakomlus Активный пользователь

    С нами с:
    12 сен 2014
    Сообщения:
    95
    Симпатии:
    19
    Адрес:
    Киев
    $flat_arr
    можно получить так
    PHP:
    1. function flatArray($arr)
    2. {
    3.         $buildValue = function ($value) use (&$result)
    4.         {
    5.                 $result[] = $value;
    6.         };
    7.  
    8.         array_walk_recursive($arr, $buildValue);
    9.  
    10.         return $result;
    11. }
    Честно, не встречал подобных задач где данный подход нужен
     
  24. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.761
    Адрес:
    :сердА
    Все бывает однажды.
    Но только именно flat. Контроля над конечной вложенностью нет. Так-то, естественно не проблема просто "собрать листья с дерева". Но и не исключаю, что мое решение можно отрефакторить. Оно довольно старое :)
     
  25. Chushkin

    Chushkin Активный пользователь

    С нами с:
    17 дек 2010
    Сообщения:
    1.032
    Симпатии:
    84
    Адрес:
    Мещёра, Центр, Болото N3
    15) Рассчитать сумму элементов многомерного массива с группировкой по ключам

    Проще всего использовать array_walk_recursive() с параметром use().

    Пример:
    PHP:
    1. // Исходные данные
    2. $in = [
    3.     'a' => 1,
    4.     'b' => 2,
    5.     'c' => 5,
    6.     'a1' => [
    7.         'a' => 1,
    8.         'b' => 2,
    9.         'c' => 5
    10.     ],
    11.     'a2' => [
    12.         'a' => 1,
    13.         'b' => 2,
    14.         'c' => 5,
    15.         'd' => 10,
    16.         'b1' => [
    17.             'a' => 1,
    18.             'b' => 2,
    19.             'c' => 5,
    20.             'f' => 100
    21.         ],
    22.         'b2' => [
    23.             'a' => 1,
    24.             'b' => 2,
    25.             'c' => 5,
    26.             'c1' => [
    27.                 'a' => 1,
    28.                 'b' => 2,
    29.                 'c' => 5,
    30.                 'f' => 100
    31.             ]
    32.         ]
    33.     ]
    34. ];
    35. // Непосредственно алгоритм
    36. $sum = [];
    37. array_walk_recursive($in, function($v, $k) use(&$sum) {
    38.   @$sum[$k] += $v;
    39.   });
    40. // Отображение результата
    41. var_dump($sum);
    42. /* array(5) {
    43.   ["a"]=> int(6)
    44.   ["b"]=> int(12)
    45.   ["c"]=> int(30)
    46.   ["d"]=> int(10)
    47.   ["f"]=> int(200)
    48. } */
     
    denis01 нравится это.