我有
13
和 range (1,13)
的数组结构;
它就像
array(1,2,3,4,5,6,7,8,9,10,11,12,13);
$slice = 2;
$ignore = 3;
我想要像
array(3,4,5,8,9,10,13);
这样的数组结构
我尝试使用
array_slice()
函数,但无法按顺序偏移该值。
array_slice($array,2,13,true);
有没有办法忽略下一个 3
值并将切片添加到下一秒直到最后一个数组,任何本机函数或键都很棒。
使用
array_merge()
,函数一可以连接两个数组切片。这将返回一个新数组。
http://php.net/manual/en/function.array-merge.php
<?php
$slice = 2;
$ignore = 3;
$a = array(1,2,3,4,5,6,7,8,9,10,11,12,13);
$a = array_merge(array_slice($a, $slice,$ignore),array_merge(array_slice($a, 2* $slice + $ignore,3), array_slice($a, 3* $slice + 2*$ignore)));
var_dump($a);
?>
我希望你明白了。 :)
这是一个函数,它将递归地对
n
长度的数组执行“非对称”切片:
function slice_asym(array $head, $exclude, $include)
{
$keep = array_slice($head, $exclude, $include);
$tail = array_slice($head, $exclude + $include);
return $tail ? array_merge($keep, slice_asym($tail, $exclude, $include))
: $keep;
}
递归需要一个基本情况,其中递归停止并且所有作用域展开并返回。在我们的例子中,我们希望当
tail
不再包含元素时停止。
array_slice()
始终返回一个数组 - 如果没有要为其给定偏移量返回的元素,则 array_slice()
返回一个空数组。因此,对于每次递归,我们想要:
切出我们想要的元素
$keep
创建一个
$tail
- 这是数组的子集,排除了我们都想忽略并保留在当前范围内的元素 ($exclude + $include
)。如果
$tail
不为空,则创建新的递归级别。否则停止递归并将所有当前 $keep
元素与下一级递归的结果合并。在伪代码中,这看起来像:
# step 1: first recursion
head = [1,2,3,4,5,6,7,8,9,10,11,12,13]
keep = [3,4,5]
tail = [6,7,8,9,10,11,12,13] # tail not empty
# step 2: second recursion
head = [6,7,8,9,10,11,12,13]
keep = [8,9,10]
tail = [11,12,13] # tail not empty
# step 3: third recursion
head = [11,12,13]
keep = [13]
tail = [] # tail empty: base case met!
# return and merge `keep` elements
[3,4,5] + [8, 9, 10] + [13] -> [3,4,5,8,9,10,13]
根据您的示例,以下调用:
$range = range(1, 13); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
$sliced = slice_asym($range, 2, 3);
print_r($sliced);
产量:
Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 8
[4] => 9
[5] => 10
[6] => 13
)
编辑
如果您使用的是 PHP 5.5 或更高版本,这也是 生成器的一个很好的用例。
这些很有用,因为:
生成器允许您编写使用 foreach 迭代一组数据的代码,而无需在内存中构建数组,这可能会导致您超出内存限制,或者需要大量的处理时间来生成。
因此,您不必预先创建顺序值数组:
相反,您可以编写一个生成器函数,它与普通函数相同,只是生成器不是返回一次,而是可以根据需要生成任意多次,以便提供要迭代的值。
我们可以为您的用例实现一个生成器,如下所示:
/**
*
* @param int $limit
* @param int $exclude
* @param int $include
* @return int
*/
function xrange_asym($limit, $exclude, $include) {
if ($limit < 0 || $exclude < 0 || $include < 0) {
throw new UnexpectedValueException(
'`xrange_asym` does not accept negative values');
}
$seq = 1;
$min = $exclude;
$max = $exclude + $include;
while ($seq <= $limit) {
if ($seq > $min && $seq <= $max) {
yield $seq;
}
if ($seq === $max) {
$min = $exclude + $max;
$max = $exclude + $include + $max;
}
$seq = $seq + 1;
}
}
并使用它,如下所示:
foreach (xrange_asym(13, 2, 3) as $number) {
echo $number . ', '; // 3, 4, 5, 8, 9, 10, 13
}
或者使用
iterator_to_array()
将整个范围生成为数组:
print_r(iterator_to_array(xrange_asym(13, 2, 3)));
希望这有帮助:)
为了优先考虑性能,请尽量减少循环/循环和函数调用。使用单个
for
循环并且不调用任何函数可能是最有效的方法,但不会因为美丽/直观的代码而赢得任何奖项。 (演示)
$limit = 13;
$skip = 2;
$keep = 3;
$result = [];
for (
$x = 1 + $skip, $k = 1;
$x <= $limit;
$x += ($k++ % $keep ? 1 : 1 + $skip)
) {
$result[] = $x;
}
var_export($result);
编写条件
continue
语句意味着浪费/无结果的迭代——因此性能较差,但也许这更容易理解。 (演示)
$limit = 13;
$skip = 2;
$keep = 3;
$result = [];
for ($x = 1; $x <= $limit; ++$x) {
if (($x - 1) % ($skip + $keep) < $skip) {
continue;
}
$result[] = $x;
}
var_export($result);
可以编写递归方法,而无需声明回调签名之外的任何变量。 (演示)
function slice_recursive(array $array, int $skip, int $keep): array
{
if (!$array) {
return $array;
}
return array_merge(
array_slice(
array_splice($array, 0, $skip + $keep),
$skip
),
slice_recursive($array, $skip, $keep)
);
}
var_export(
slice_recursive(range(1, 13), 2, 3)
);
也可以编写类似的非递归方法。在此脚本中,输入数组的消耗实际上将原始数组减少为空数组。 (演示)
$limit = 13;
$skip = 2;
$keep = 3;
$result = [];
$array = range(1, 13);
while ($array) {
array_push(
$result,
...array_slice(
array_splice($array, 0, $skip + $keep),
$skip
)
);
}
var_export($result);
将会有更多的方法来满足任务要求。通常,微优化性能是不必要的——选择您理解并可以维护的脚本。