Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: Перебор глобального массива в цикле foreach в рекурсии
Теперь и на Денвере и на сервере корректно выводятся все элементы:
- Первый
- Третий
- Четвертый
- Второй
- Пятый
- Шестой
Вопрос в том, почему так происходит?
Есть подозрение, что дело во внутреннем указателе массива $items, но насколько я знаю, foreach использует копию массива (т.е. не вносит изменений в исходный массив) и сбрасывает внутренний указатель массива на начало перед обходом.
Покинул форум
Сообщений всего: 332
Дата рег-ции: Март 2010 Откуда: Таджикистан, Худжанд
Помог: 0 раз(а)
[+]
странно, но в PHP 4.4.9 вроде бы должен работать первоначальный ...
Champion
Отправлено: 31 Марта, 2010 - 09:24:27
Активный участник
Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008 Откуда: Москва
Помог: 57 раз(а)
Так сходу не видно. А попробуй в функции сделать var_dump($items). Будет различаться в 5 и в 4 PHP?
JustUserR
Отправлено: 31 Марта, 2010 - 09:26:35
Активный участник
Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009
Помог: 17 раз(а)
Uchkuma пишет:
Есть подозрение, что дело во внутреннем указателе массива $items
Скорее всего так - это можно проверить если заменить foreach на обычный цикл со счетчиком и явным перебором элементов
Конкретно дело в том что видимо ранее глобальные элементы передавались по ссылке и счетчик для них был общий - как вариант можно было при входе сохранять позицию с помощью current и при выходе выставлять ее на сохраненную
Ваше же решение просто копирует массив и у него появляется свой независимый счетчик
----- Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
Uchkuma
Отправлено: 31 Марта, 2010 - 16:00:36
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
JustUserR, я так и подумал. В каждой последующей рекурсии items() перебор массива $items начинается не с первого элемента, и после n-ной рекурсии, когда последний элемент массива был достигнут, циклы foreach предыдущих рекурсий тоже завершаются.
Я так понимаю, мое решение является нерациональным, т.к. $items будет каждый раз копироваться и это приведет к излишнему потреблению памяти? Особенно если очень много элементов в массиве?
JustUserR пишет:
как вариант можно было при входе сохранять позицию с помощью current и при выходе выставлять ее на сохраненную
Насколько я знаю, current() возвращает значение текущего элемента. Не понимаю, как с помощью него можно сохранить позицию? Может вы имели ввиду функцию key()?
Если я с помощью key() сохраню индекс последнего обработанного элемента перед следующей рекурсией, то как после нее с помощью этого индекса вернуть указатель на этот элемент?
В принципе, я представляю как это все можно сделать при помощи for со счетчиком, но я стараюсь им не пользоваться для перебора массивов без особой необходимости, тем более, что для этой цели предназначен foreach.
Ch_chov
Отправлено: 31 Марта, 2010 - 16:33:20
Постоянный участник
Покинул форум
Сообщений всего: 2121
Дата рег-ции: Июль 2008 Откуда: из города
В принципе, я представляю как это все можно сделать при помощи for со счетчиком, но я стараюсь им не пользоваться для перебора массивов без особой необходимости, тем более, что для этой цели предназначен foreach.
А for с массивами вроде даже быстрей работает чем foreach.
Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009
Помог: 17 раз(а)
Uchkuma пишет:
JustUserR, я так и подумал. В каждой последующей рекурсии items() перебор массива $items начинается не с первого элемента, и после n-ной рекурсии, когда последний элемент массива был достигнут, циклы foreach предыдущих рекурсий тоже завершаются.
Я так понимаю, мое решение является нерациональным, т.к. $items будет каждый раз копироваться и это приведет к излишнему потреблению памяти? Особенно если очень много элементов в массиве?
Все совершенно верно говорите
Вероятно ваш способ будет работать оптимально если попробовать передавать массив по ссылке с помощью & - хотя по смысло это схоже с проблемной ситуацие но реализация вероятно без бага
Uchkuma пишет:
Насколько я знаю, current() возвращает значение текущего элемента. Не понимаю, как с помощью него можно сохранить позицию? Может вы имели ввиду функцию key()?
Если я с помощью key() сохраню индекс последнего обработанного элемента перед следующей рекурсией, то как после нее с помощью этого индекса вернуть указатель на этот элемент?
Все делается достаточно просто - ведь проблема в том что вложенная рекурсивная функция меняет счетчик у внешней функции - значит необьходимо при входе на шаг рекурсии сохранить позицию счетчика (Она будет показывать позицию счетчика у рекурсивной функции более верхнего уровня) потом сбросить его и провести свой цикл и вернуть индекс обратно - таким образом после завершения шага рекурсии вызывавшая функция продолжит цикл с нужного места
Uchkuma пишет:
В принципе, я представляю как это все можно сделать при помощи for со счетчиком, но я стараюсь им не пользоваться для перебора массивов без особой необходимости, тем более, что для этой цели предназначен foreach.
На самом деле эти операторы очень похожи и взаимозаменяемы - учитывая что язык PHP берет свои начала от языка Perl где между ними вообще нет разницы
----- Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
Uchkuma
Отправлено: 31 Марта, 2010 - 21:52:18
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
JustUserR пишет:
значит необьходимо при входе на шаг рекурсии сохранить позицию счетчика (Она будет показывать позицию счетчика у рекурсивной функции более верхнего уровня) потом сбросить его и провести свой цикл и вернуть индекс обратно
Что-то я не догоняю :( Как же все-таки вернуть индекс обратно? Что-то у меня никак не вырисовывается картина. JustUserR, можно ли поподробнее?
Придумал еще один банальный способ, не добавляя массив в параметры функции. В первом варианте добавил после глобализации строчку $items_copy = $items; и в цикле уже работаем с $items_copy. Но это опять же плодит массивы до неизвестного количества, а хотелось бы работать с одним массивом оперируя лишь его указателем.
По поводу:
JustUserR пишет:
Вероятно ваш способ будет работать оптимально если попробовать передавать массив по ссылке с помощью & - хотя по смысло это схоже с проблемной ситуацие но реализация вероятно без бага
однако нет. Ситуация аналогичная. В PHP5 работает, в PHP 4.4.9 - нет.
Ch_chov пишет:
А for с массивами вроде даже быстрей работает чем foreach.
Возможно, но не всегда. foreach перебирает элементы массива по порядку, а for по счетчику, т.е. по индексу. А если в массиве элементы начинаются не с нуля или есть пропуски (некоторые элементы были unset)? А если ключи строковые, а не числовые? Тогда прибегаем к использованию еще одной функции - each(). Неужели использование двух функций будет работать быстрее чем одна? Но это уже оффтоп... Простите, for это не функция ))
Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008 Откуда: Москва
Помог: 57 раз(а)
Uchkuma пишет:
В принципе, я представляю как это все можно сделать при помощи for со счетчиком, но я стараюсь им не пользоваться для перебора массивов без особой необходимости, тем более, что для этой цели предназначен foreach.
Для этой цели предназначен for. foreach преднезначен для тех случаев, когда ты не знаешь ключи массива. И да, foreach работает медленне.
Uchkuma
Отправлено: 01 Апреля, 2010 - 10:31:57
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
Champion пишет:
Для этой цели предназначен for. foreach преднезначен для тех случаев, когда ты не знаешь ключи массива.
Так и есть, я могу не знать ключи массива.
JustUserR
Отправлено: 01 Апреля, 2010 - 17:48:25
Активный участник
Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009
Что-то я не догоняю Как же все-таки вернуть индекс обратно? Что-то у меня никак не вырисовывается картина. JustUserR, можно ли поподробнее?
Как вариант придется вводить специальные счетчики для сохранения текущей позиции и перевода номера текущего элемента с помощью reset/next
Однако лучше использовать простой цикл $for и вышеприведенную функцию для получения списка ключей
Uchkuma пишет:
Придумал еще один банальный способ, не добавляя массив в параметры функции. В первом варианте добавил после глобализации строчку $items_copy = $items; и в цикле уже работаем с $items_copy. Но это опять же плодит массивы до неизвестного количества, а хотелось бы работать с одним массивом оперируя лишь его указателем
Хм но ведь можно проверять уровень сложенности рекурсии (В вашем случае по номеру родительского элемента в массиве) и во всех внутренних шагах рекурсии уже не призводить данное копирование
----- Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
Uchkuma
Отправлено: 01 Апреля, 2010 - 21:38:20
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
JustUserR, спасибо! Действительно, самое рациональное решение с array_keys() и циклом for. Теперь мы не зависим от внутреннего указателя массива, массив лишний раз не копируем и нам не нужны никакие специальные счетчики текущей позиции!
Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009
Помог: 17 раз(а)
Uchkuma пишет:
JustUserR, спасибо! Действительно, самое рациональное решение с array_keys() и циклом for. Теперь мы не зависим от внутреннего указателя массива, массив лишний раз не копируем и нам не нужны никакие специальные счетчики текущей позиции!
Пожалуйста! В PHP имеется очент много встроенных функций для работы с массивами поэтому для большинсва задач уже есть готовая функция или их комбинация
----- Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
skeef
Отправлено: 11 Июля, 2015 - 13:14:04
Новичок
Покинул форум
Сообщений всего: 2
Дата рег-ции: Июль 2015
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.