Вопрос по PHP

12 3
Solmyr
На сайте с 10.09.2007
Offline
501
1333

Нужно итеративно проходя по массиву, выкидывать из него некоторые элементы, что должно сокращать итерацию. Как сделать.

Чтобы объяснить что я хочу


$arr = array('a'=>'a','b'=>'b','c'=>'c');

foreach($arr as $key=>$vl){
echo $key.'-'.$vl."\n";
if($vl=='a'){
unset($arr['b']);
}
}

Хотелось бы чтобы такой код выдавал:

a-a

c-c

Но он естественно выдает

a-a

b-b

c-c

Как можно решить задачу? Смысл состоит в том, что какие элементы можно (и нужно) выкинуть и итерации выясняется в ходе итерации. На самом деле на месте оператора $vl=='a' как здесь в коде, стоит некая потребляющая много ресурса функция, которую нужно выполнять пореже.

KOROLEV
На сайте с 10.04.2009
Offline
78
#1

непонятно зачем?

можно использовать


if($vl=='b')
continue;

Или еще вариант - прогнать цикл и сформировать необходимый массив

Чуть не забыл - ну и естественно надо сначала проверить, потом выводить)))

Solmyr
На сайте с 10.09.2007
Offline
501
#2
KOROLEV:
непонятно зачем?

можно использовать

Нельзя. Обратите внимание, при анализе элемента 'a' выясняется что можно выкинуть элемент 'b'.

KOROLEV:
Или еще вариант - прогнать цикл и сформировать необходимый массив

Если прогнать полный цикл - это нерациональное использование вычислительного ресурса, т.к. анализируя элемент 'a' мы понимаем, что элемент 'b' можно не анализировать. А если прогонять полный цикл - его придется анализировать.

orphelin
На сайте с 02.07.2006
Offline
261
#3

Solmyr, а если создать еще один пустой массив и в него записывать фильтруемые элементы и и перед анализом проверять a!=b?

S
На сайте с 23.05.2004
Offline
305
#4

Имхо никак. Массив начал разбираться до начала анализа, т.е работа идет с уже разобранным по элементам массивом.

Это просто подпись.
Solmyr
На сайте с 10.09.2007
Offline
501
#5
orphelin:
Solmyr, а если создать еще один пустой массив и в него записывать фильтруемые элементы и и перед анализом проверять a!=b?

Да, это первое что приходит в голову. Но это костыль, дублирование данных. Хочется сделать не "абы как шоб работало", а максимально оптимально. Может быть как-то можно решить эту задачу, изменив исходное представление данных?

---------- Добавлено 25.02.2016 в 23:29 ----------

Полностью задача выглядит так. Есть некая дискретная последовательность элементов, пусть числовой ряд. На эту последовательность наложены отрезки разной длины (в основном короткие), отрезки взаимно перекрываются, про отрезки известно начало и их длина (в общем все что характеризует отрезки). Требуется из массива отрезков выкинуть все отрезки которые полностью перекрываются каким либо одним другим отрезком (если отрезки равны - то не выкидывается ни один, выкидываются при условии если длина одного строго больше чем длина другого). Выполнить максимально быстро. В том числе, задача должна выполняться максимально быстро и в случае если всего отрезков мало, экономия времени должна быть не только на оптимизации перебора но и на оптимизации самого процесса "выкидывания". Исходные данные, уже изначально сортированы по точке начала отрезка, можно это использовать, можно не использовать.

LEOnidUKG
На сайте с 25.11.2006
Offline
1678
#6

Только дублировать массив и точка. Ничего страшного, прогнать массив не долго.

✅ Трастовых площадок под размещение статей и ссылок. Опыт 15 лет! ( https://searchengines.guru/ru/forum/675690 ) ⭐ Купить вечные трастовые ссылки для сайта ( https://getmanylinks.ru/?srh ) ⭐ Новый аналог AllSubbmitter https://getmanylinks.ru/getmanysubmits.html (Бесплатное демо)
Solmyr
На сайте с 10.09.2007
Offline
501
#7
LEOnidUKG:
Ничего страшного, прогнать массив не долго.

Один раз не долго, а сделать такую операцию 100000 раз - долго. Требуется реализовать алгоритм, который будет не просто работать, а работать максимально быстро, насколько позволяет математика. Не хочется только из-за того что php это не может переходить на какой-то другой язык...

doctorpc
На сайте с 12.07.2009
Offline
112
#8

Не совсем понятно какие ключи выкидывать нужно. Почему имменно unset($arr['b'])? Т.к. b следующий элемент за текущим или какое-то другое условие?

Но если конкретно по этой задаче. То быстро пришли вот такие решения на ум:

Вариант 1:


$arr = array('a'=>'a','b'=>'b','c'=>'c');
foreach ($arr as $key =>&$vl) {
echo $key.'-'.$vl."\n";
if($vl=='a'){
unset($arr['b']);
}
}

Вариант 2:


$arr = array('a'=>'a','b'=>'b','c'=>'c');
$skipKey = null;
foreach ($arr as $key =>$vl) {
if ($key == $skipKey) {
$skipKey = null;
continue;
}
echo $key.'-'.$vl."\n";
if($vl=='a'){
$skipKey = 'b';
}
}
LEOnidUKG
На сайте с 25.11.2006
Offline
1678
#9
Один раз не долго, а сделать такую операцию 100000 раз - долго.

Долго это сколько миллисекунд?

Solmyr
На сайте с 10.09.2007
Offline
501
#10

doctorpc, Удивительно, но первый вариант сработал. Спасибо огромное. Я три раза перечитал описание foreach, думал о таком решении, но не попробовал. Почему-то подумал что работать не будет. Сейчас попробовал - работает.

12 3

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий