获取数组

时间:2017-08-04 20:06:10

标签: php arrays math offset

TL; DR

如何切割数组以在给定偏移量(也是用户定义的)之前和之后获得(用户定义的)条目数而不超出范围。 E.g:

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

如果定义了2的限制和索引3(D)的起始偏移量,则例程应该返回BCDE:两个之前D只有一个D,否则会超出范围。

如果定义了3的限制和索引0(A)的起始偏移量,则例程应返回ABCDA之前没有,否则它也会超出范围。

  

切片必须扩展为始终在$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工作正常。我强迫第一次偏移以避免负面偏移。

然后我首先想到我可以通过 2 增加$limit以获得"第二个偏移",当然它没有用,但是那是我的错。我经常不使用该功能>。<

然后我将$end的逻辑更改为:

$end = $offset + $limit + 1;

我在集合中找到的偏移量,加上限制以及另外一个包含$offset中存储的条目的偏移量。它工作正常,直到$offset设置为4(E)或更多。在那之后,对于字母' F'切片上升到G,H上升到I等等o.O

我试图寻找解决方案但到目前为止我能找到的是涉及循环和复杂条件。据我所知,我不应该这样做,毕竟如果它是连续的,我可以申请"简单"数学就好了。

但是我没有工作所以我可能错了......

3 个答案:

答案 0 :(得分:2)

再次编辑。
这可能与您可能实现的功能一样轻 它将起始值和结束值与最大值和最小值进行比较,以确保它不会溢出/下溢 输出它使用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} - 匹配0到6次之间的任何内容 B - 字面上匹配&#34; B&#34; .{0,6} - 再次匹配0到6次之间的任何内容。

在正则表达式模式中,我使用chr()将数字($ offset)转换为大写字母 在这种情况下,偏移量为1,这意味着字母表中的第二个字母(A为0) $ limit用于限制正则表达式搜索。 {0,<$limit>}这意味着在0和$ limit之间尽可能多地匹配。

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,否则不是 最大限度的结束限制无法正常工作,谢谢你指出了这一点 如果limit为0错误消息。

我想我现在所有的变化都在起作用。

答案 1 :(得分:-1)

这是您最干净的方法 - 无需条件计算。

代码:(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

输出:

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

我可以确认array_fill_keys()同样适用array_fill()。这是另一个演示:

代码:(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";
}

输出:

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',
)
---

答案 2 :(得分:-3)

此处的解释:https://stackoverflow.com/a/45532145/1636522

顺便说一下,我打败了他们:https://3v4l.org/5Gt7B/perf#output :-P

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(", ") + "]"
  );
}