За последние 24 часа нас посетили 36407 программистов и 1537 роботов. Сейчас ищут 1258 программистов ...

поиск по массиву, хранение данных

Тема в разделе "PHP для новичков", создана пользователем VLK, 11 авг 2016.

  1. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Смотрите, есть массив типа:
    PHP:
    1. $base = [ '122', 'a111', '234233' ];
    значения в нем являются уникальными, цифры и символы, от 1 до 20 символов длина, естественно их на много больше, десятки тыщ, по этому массиву будет очень часто осуществляться поиск, найти схождение, найти расхождение, ну типа есть какие то массивы и нужно выявить какие значения из этих массивов есть в $base или каких нет в $base.

    вопрос как хранить что бы был быстрый поиск, первый вариант это хранить так, как есть сейчас и выбирать при помощи array_intersect и array_diff, но это занимает какое то время.

    второй вариант, перевести значения в ключи, что бы было что то типа:
    PHP:
    1. $base = [ '122' => NULL, 'a111' => NULL, '234233' => NULL ];
    и осуществлять поиск через цикл используя array_key_exists:
    PHP:
    1. $base = [];
    2. $arr = []; // тут значения не в виде ключей
    3. for($i = 0; $i < count($arr); $i++) {
    4.     if (array_key_exists($arr[$i], $base)) {
    5.         // какое то действие
    6.     }
    7.     // кстати isset($base[ $arr[$i] ]) почему то уже не срабатывает
    8. }
    как то так, такой вариант работает мгновенно, за 0 сек выполняется в отличии от первого (где то 10 сек при тестировании), но меня как то смущает что хранится в виде ключей..
    массив будет записываться в файл.

    кто что скажет из профессионалов.
     
  2. denis01

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

    С нами с:
    9 дек 2014
    Сообщения:
    12.227
    Симпатии:
    1.714
    Адрес:
    Молдова, г.Кишинёв
    Для in_array скорость замерял?
     
  3. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    ну у меня как минимум 2 массива, первый основной $base а второй какой то и я искал только при помощи array_intersect и array_diff, по этому in_array не измерял, сейчас измерил, где то раз в 100 медленнее.
    --- Добавлено ---
    сейчас присмотрелся, что то когда в виде ключей я храню и проверяю через array_key_exists, работает не корректно, до этого показывало сколько должно было, сейчас почему то меньше..
     
  4. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    @VLK, я попробовал так:
    PHP:
    1. $count = 100000;
    2. for ($i = 0; $i < 100000; $i++) {
    3.     $base[] = $count--;
    4. }
    5. $search = ['122', 444, 9999];
    6. $search = array_flip($search);
    7. var_dump(array_intersect_key($base, $search));
    8. /*вывод:
    9. array (size=3)
    10.   122 => int 99878
    11.   444 => int 99556
    12.   9999 => int 90001
    13. */
     
    VLK нравится это.
  5. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Странно если тип ключа будет string то не находится. В документации вроде показывают что работает.
    --- Добавлено ---
    Все работает как надо, я забыл сохранить новое состояние $base;
    т.е. не хватает строчки :
    PHP:
    1. $base = array_flip($base)
     
    VLK нравится это.
  6. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Зачем такую глупость делать?
    http://secure.php.net/manual/ru/function.array-search.php

    не ?
    --- Добавлено ---
    PHP:
    1. $start = microtime(true);
    2.             // тело скрипта
    3.  
    4.         $newarr = [
    5.            '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    6.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    7.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    8.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    9.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    10.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    11.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    12.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    13.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    14.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    15.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    16.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    17.             '12qrwrq','12qrwrq','12qrwrq','12qrwrq','12qrwrq',
    18.            'search',
    19.             '12wegwegwegqrwrq', '12qrwwegwegrq', '12qrwregwegq', '12qweerwrq', '12qrwrwegwegwegq', '12qrwrqewgweg', '12qrwrqwegweg', '12qrwrewgwegq', '12qrwrefeg', '12qrwrq', '12qrwrq', '12qrwrq'
    20.         ];
    21.         $key = array_search('search', $newarr);
    22.         echo $newarr[$key].'<br>';
    23.         $t = (microtime(true) - $start);
    24.         print 'Время выполнения скрипта: '.number_format($t).' сек.';
    Время выполнения!
    0 сек.
    Результат на экране:
    search
    Время выполнения скрипта: 0 сек.

    Можно в другом формате.

    search
    Время выполнения скрипта: 3.0994415283203E-6 сек.

    И даже с массивом раз в 30 больше попробовал тоже 0 сек. В чём проблема. Два массива ?

    Слей в один. Смотри всё просто:
    http://secure.php.net/manual/ru/function.array-merge.php
     
    #6 askanim, 12 авг 2016
    Последнее редактирование: 12 авг 2016
    VLK нравится это.
  7. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    @askanim, не глупость это. Особенность массивов пыха такая. Где-то в соседней теме @rodent90 приводил пример того, как хранятся значения. По ключам же поиск фактически нативный, от того и скорость выше. Потому при прочих равных лучше искать по ним.
     
  8. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @romach попробуй, то что я написал вставь и замерь скорость я привёл же результаты.
     
  9. Ganzal

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

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    @askanim напиши мне бенчмарк - я погоняю у себя.
     
  10. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    @askanim у меня 2 массива, мне надо выбрать все значения из одного, которых нет в другом:

    PHP:
    1. $base = []; // около 30 000 записей
    2. $input = []; // около 20 000 записей
    3. // оба массива формата: [ 0 => 'key1', 1 => 'key2' ]

    и in_array тут не канает, короче так:
    PHP:
    1. $count = 0;
    2. for($i = 0; $i < count($input); $i++) {
    3.     $key = $input[$i];
    4.     if ( !in_array($key, $base) ) {
    5.         $count++;
    6.     }
    7. }
    1 проход выполняется за 165 сек.

    PHP:
    1. $base = array_flip($base);
    2.  
    3. $count = 0;
    4. for($i = 0; $i < count($input); $i++) {
    5.     $key = $input[$i];
    6.     if ( !array_key_exists($key, $base) ) {
    7.         $count++;
    8.     }
    9. }
    50 проходов за 0 сек.


    PHP:
    1. $count = count( array_diff($input, $base) );
    50 проходов за 4 сек.

    PHP:
    1. $base = array_flip($base);
    2. $input = array_flip($input);
    3.  
    4. $count = count( array_diff_key($input, $base) );
    50 проходов за 0 сек.
     
    #10 VLK, 12 авг 2016
    Последнее редактирование: 12 авг 2016
  11. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @VLK я наверху показал код поиска по значениям, который работает не медленнее твоего.
     
  12. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    @mahmuzar спасибо за array_flip, как то я его упустил.
    --- Добавлено ---
    @askanim ты выше показал поиск одного значения, у меня их массив с 20 000 записей.
     
  13. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @VLK тогда я не понял задачу, я думал у тебя задача найти значение среди 20 000 записей.
     
  14. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Когда записей становится дохрена, пых начинает вести себя чуть иначе и небольшая разница становится таки значительной. Тестировать нужно именно на десятках тысячах записей, желательно с примерно таким же содержимым.
     
  15. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @romach я же сказал, я сунул туда порядка 5 или 6 тысяч.
    --- Добавлено ---
    @romach и 0 сек показало
    --- Добавлено ---
    @romach вот попробовали бы то что я написал и посмотрели бы все вместе на результат, ноги не кому за то что попробовать можно, никто и кому рубит ьне собирается вроде.
     
  16. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Пиши бенчмарк, 20-30к. записей, что бы и просто массивы и SPL и разные варианты поиска. Пусть @Ganzal позапускает у себя на разных версиях пыха )
     
  17. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @romach я на 7-ке сделал.
    --- Добавлено ---
    @romach да я просто написал вариант я не говорю делать именно так.
    --- Добавлено ---
    @Ganzal Завтра утром по своему времени в эту тему закину.
    Потому что я уже ухожу, офис закрывается, а я еду не домой, так как сегодня пятница и пора бы отдохнуть за недельку.
    Поправка по твоему времени*.
     
  18. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Вот файл возвращающий гигантский массив...
    Но мне кажется там просто много у меня там гигантский.... там более 50к наверно даже.
    Короче вот код.

    PHP:
    1. $arr = require_once ROOT.'/rArr.php';
    2. $t = (microtime(true) - $start);
    3. $key = array_search('search', $arr);
    4. echo $arr[$key].'<br>';
    5. print 'Время выполнения скрипта: '.number_format($t).' сек.';
    А вот сам файл который массив возвращает.
    https://yadi.sk/i/-IVy4NJVuAHrp

    Ссылка на скачивание файла.

    Сюда не влез слишком большой. 1 с фигом метра массив весит.
    --- Добавлено ---
    там за 100к значений в массиве, и обработка составила 1,4 секунды. По мне так это быстро для обработки массива то. А вообще мне кажется для такого изощрения нужны базы данных.
     
  19. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    @VLK, ты можешь отказаться от цикла, используй https://secure.php.net/manual/ru/function.array-intersect-key.php/

    т.е. этот код:
    PHP:
    1. $base = array_flip($base);
    2. $count = 0;
    3. for($i = 0; $i < count($input); $i++) {
    4.     $key = $input[$i];
    5.     if ( !array_key_exists($key, $base) ) {
    6.         $count++;
    7.     }
    8. }
    можно написать так:
    PHP:
    1. $base = array_flip($base);
    2. $input = array_flip($input);
    3.  
    4. var_dump(array_intersect_key($base, $search));
    мне показалось он возвращает именно тот результат который тебе нужен.
     
    askanim нравится это.
  20. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @mahmuzar попробуй протестить у себя мой метод скажи какой результ даст
    --- Добавлено ---
    @romach могу завтра полностью задачу раскидать, написать несколько вариантов решения на мой взгляд. Но махмузар тоже дело предложил.
     
  21. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    @askanim, твой код не пожходит для @VLK. У него условия задачи другие.
     
    askanim нравится это.
  22. MiksIr

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

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Строчки местами перепутаны
     
  23. Ganzal

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

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    @askanim у тебя в файле данные повторяются. Для честности тестирования с другими методами - данные должны быть уникальны, наверное. Выкладывай завтра полные бенчсьюит, чтоб распаковал, запустил, получил результаты. Будет дополнительным плюсом, если результаты будут в человекодружелюбном виде выходить. Вроде такого:

    ru_php_forum_59355.png
     
  24. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Ну и до кучи:
     
    Anhk и askanim нравится это.
  25. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    @VLK, ты скорее всего поймешь, но все же, выше в моем коде вместо $search - $input
     
    VLK нравится это.