Get offset neighbors of an array

左心房为你撑大大i 提交于 2019-12-04 21:57:16

This is your cleanest approach -- no conditional calculations required.

Code: (Demo)

$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

Output:

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

I can confirm that array_fill_keys() works just as well in place of array_fill(). Here is another demo:

Code: (Demo)

$collection = range('A', 'Z');
for ($i = 0; $i < 5; ++$i) {
    $offset = rand(0, 25);
    $limit = rand(1, 5);
    echo "Offset: $offset\nLimit: $limit\n";
    var_export(array_intersect_key($collection, array_fill_keys(range($offset-$limit, $offset+$limit), null)));
    echo "\n---\n";
}

Output:

Offset: 13
Limit: 3
array (
  10 => 'K',
  11 => 'L',
  12 => 'M',
  13 => 'N',
  14 => 'O',
  15 => 'P',
  16 => 'Q',
)
---
Offset: 0
Limit: 5
array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'E',
  5 => 'F',
)
---
Offset: 12
Limit: 2
array (
  10 => 'K',
  11 => 'L',
  12 => 'M',
  13 => 'N',
  14 => 'O',
)
---
Offset: 25
Limit: 3
array (
  22 => 'W',
  23 => 'X',
  24 => 'Y',
  25 => 'Z',
)
---
Offset: 11
Limit: 5
array (
  6 => 'G',
  7 => 'H',
  8 => 'I',
  9 => 'J',
  10 => 'K',
  11 => 'L',
  12 => 'M',
  13 => 'N',
  14 => 'O',
  15 => 'P',
  16 => 'Q',
)
---

Edit again.
This is probably as light as you can possibly make this function.
It compares the start and end values with max and min to make sure it doesn't overflow/underflow.
The to output it uses a substr().
But you can also loop it or explode it. See link for that code.
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);



Edit I think I found the best solution. 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);

Sorry for not including an explanation.
I build a regex pattern looking like .{0,6}B.{0,6} but 6 and B is variable from the inputs. This means:
.{0,6} - match anything between zero and six times.
B - match a "B", literally.
.{0,6} - match anything between zero and six times again.

In the regex pattern I use chr() to convert a number ($offset) to a capital letter.
In this case offset is 1 so that means the second letter in alphabet (A is 0).
The $limit is used to, well limit the regex search. {0, <$limit>} this means match as many as you can between 0 and $limit.

https://3v4l.org/BVdiF

No calculations or array functions at all. Just a regex.


Not sure if I got it correct this time.
But calculate the start and end values of array slice depending on if you overflow or underflow on the offset limit.

$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

Edit found some issues.
If start is 0 I needed to add 1, not otherwise.
End limit of max was not working as it should, thanks for pointing that out.
If limit is 0 error message.

I think I got all variations working now.

Explanations here : https://stackoverflow.com/a/45532145/1636522.

By the way, I beat them all : https://3v4l.org/5Gt7B/perf#output :-P

PHP version :

$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 version :

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(", ") + "]"
  );
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!