Intereting Posts
max_input_vars и ACF чтение docx (Office Open XML) в PHP Предотвращение таймаута во время большого запроса в PHP 401 Ошибка аутентификации, когда SoapClient пытается получить файл схемы Неопределенная переменная: user laravel Настройка переменной окружения PHP при запуске сценария командной строки Программно отключить определенные функции PHP для тестирования Пытается использовать PHP DateTime Class с Yii2, получившим класс не найденных ошибок Расшифровать строку в C #, которая была зашифрована с помощью PHP openssl_encrypt Google Maps не может полностью загрузиться в jQuery nav-tab Где найти php_imagick.dll для php 5.5.12 для Windows wampserver 2.5? Каковы различия между обратным ходом и одинарной кавычкой? Могу ли я использовать оператор IF в запросе, как указано выше? PHP: Как проверить, существует ли файл изображения? Как перенести список жанров в SQL в отдельную базу данных Кто-нибудь знает хороший PHP ORM, который НЕ использует PDO?

Получить смещенные соседи массива

TL; DR

Как я могу нарезать массив, чтобы получить (определяемое пользователем) количество записей до и после заданного смещения (также определяемого пользователем) без выхода за пределы диапазона. Например:

$collection = [ 'A', 'B', 'C', 'D', 'E' ]; 

Если задано ограничение 2 и начальное смещение индекса 3 (D), процедура должна возвращать B , C , D , E : два перед D и только один после D , иначе он выйдет за пределы диапазона.

Если определено ограничение 3 и начальное смещение индекса 0 (A), подпрограмма должна возвращать A , B , C , D , три после A и ни один до нее, иначе она также выйдет за пределы диапазона.

Кусочек должен расширяться, чтобы всегда приводить количество элементов, определяемых $limit до и после записи, найденной в $offset . Если одна из сторон не выходит за пределы диапазона, конечно


Я пытаюсь понять простой, возможно, математический способ, чтобы получить смещенные соседи индексированного (и в настоящее время последовательного) массива, но с пользовательским лимитом.

Первое, что пришло ко мне, это использовать array_slice () :

 $collection = range( 'A', 'Z' ); $offset = 0; //rand( 0, 25 ); $limit = 3; $length = count( $collection ); if( $offset >= $length ) { throw new \OutOfRangeException( 'Requested offset exceeds the size of Collection' ); } $start = ( $offset - $limit ) >= 0 ? ( $offset - $limit ) : 0; $end = $limit + 2; $slice = array_slice( $collection, $start, $end ); 

Из того, что я мог проверить, $start работает нормально. Я заставляю первое смещение избегать отрицательного.

Тогда я сначала подумал, что могу просто увеличить $limit на 2, чтобы иметь «второе смещение», и, конечно, это не сработало, но это была моя самая ошибка. Я не часто использую эту функцию>. <

Затем я изменил логику $end на:

 $end = $offset + $limit + 1; 

Смещение, которое я нашел в коллекции, плюс предел и еще один, чтобы включить самую запись, хранящуюся в $offset . Он работал нормально до тех пор, пока $offset будет установлен на 4 (E) или больше. После этого, для буквы «F» ломтик поднимался до G, H до I и так далее oO

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

Но мой не работал, поэтому я могу ошибаться …

Это ваш самый чистый подход – никаких условных вычислений не требуется.

Код: ( Демо )

 $collection = range( 'A', 'Z' ); $offset = 1; //rand( 0, 25 ); $limit = 3; $indices=array_flip(range($offset-$limit,$offset+$limit)); // genereate offset range and flip values to keys //var_export($indices); /*array ( -2 => 0, -1 => 1, 0 => 2, 1 => 3, 2 => 4, 3 => 5, 4 => 6, )*/ var_export(array_intersect_key($collection,$indices)); // retain values with listed keys 

Вывод:

 array ( 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', ) 

Изменить снова.
Это, вероятно, так же легко, как вы можете сделать эту функцию.
Он сравнивает начальные и конечные значения с max и min, чтобы убедиться, что он не переполняется / нисходит.
Для вывода он использует substr ().
Но вы также можете зацикливать его или взорвать. См. Ссылку для этого кода.
https://3v4l.org/sfCKY

 $alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $offset = 1; $limit = 6; $start = max(0, $offset-$limit); //if offset-limit is negative value max() makes it 0 $end = min(strlen($alpha)-1, $offset+$limit); // if offset+limit is greater than str lenght min will make it str lenght. Echo substr($alpha, $start, $end-$start+1); 


Редактировать Я думаю, что нашел лучшее решение. Preg_match.

 $collection = range( 'A', 'Z' ); $offset = 1; $limit = 6; $alpha = implode("", $collection); Preg_match("/.{0," . $limit ."}" . chr(65 +$offset) . ".{0," . $limit ."}/", $alpha, $match); Var_dump($match); 

Извините за отсутствие объяснения.
Я создаю шаблон регулярного выражения, похожий на .{0,6}B.{0,6} но 6 и B переменны от входов. Это означает:
.{0,6} – сопоставить что угодно между нулем и шестью раз.
B – буквально «B».
.{0,6} – повторить все, что угодно, от нуля до шести раз.

В шаблоне regex я использую chr () для преобразования числа ($ offset) в заглавную букву.
В этом случае смещение равно 1, что означает вторую букву в алфавите (A равно 0).
Предел $ используется, чтобы ограничить поиск регулярных выражений. {0, <$limit> } означает совпадение с числом до 0 и $.

https://3v4l.org/BVdiF

Никаких вычислений или функций массива вообще. Просто регулярное выражение.


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

 $collection = [ 'A', 'B', 'C', 'D', 'E' ]; $offset = 4; $limit = 2; If($offset>count($collection) || $offset < 0 || $limit ==0) die("inputs out of bounds"); If($offset-$limit >=0){ $start = $offset-$limit; }else{ $start =0; } If($offset+$limit>count($collection)){ $end = count($collection)-$offset+$limit; }else{ $end = $offset + $limit; } If($start ==0) $end++; $result = array_slice($collection, $start, $end-$start+1); Var_dump($result); 

https://3v4l.org/0l1J6

Редактировать нашли некоторые проблемы.
Если start 0, мне нужно добавить 1, а не иначе.
Конечный предел max не работал должным образом, спасибо, что указали это.
Если предел равен 0 сообщению об ошибке.

Думаю, теперь у меня все изменения.

Объяснения здесь: https://stackoverflow.com/a/45532145/1636522 .

Кстати, я избил их всех: https://3v4l.org/5Gt7B/perf#output 😛

Версия PHP:

 $padding = 2; $letters = range('A', 'Z'); $indexes = ['-1', ' 0', ' 1', ' 2', '13', '24', '25', '26']; foreach ($indexes as $index) { $i = intval($index); echo $index . ' ' . ( isset($letters[$i]) ? $letters[$i] : '/' ) . ' [' . implode(', ', array_slice( $letters, $i - min($i, $padding), $padding + 1 + min($i, $padding) )) . ']' . "\n"; } 

Версия JS:

 padding = 2; letters = new Array(27).join(" ").split(""); letters = letters.map((x, i) => (i + 10).toString(36)); indexes = ["-1", " 0", " 1", " 2", "13", "24", "25", "26"]; for (i = 0; i < indexes.length; i++) { index = parseInt(indexes[i], 10); s = letters.slice( index - Math.min(index, padding), padding + index + 1 ); console.log( indexes[i], letters[index] || "/", "[" + s.join(", ") + "]" ); }