我已经尝试了很长一段时间,使用了各种解决方案,包括array_combine()
、array_keys()
、array_values()
等,但我的解决方案都无法正常工作。
基本上说,我们有一个按特定顺序的关联数组,我正试图改变它的位置——无论是相对的还是绝对的,这都无关紧要。这段代码展示了我的错误、低效的版本:
<?php
$testArray = [
'a' => 'Item 1',
'b' => 'Item 2',
'c' => 'Item 3',
'd' => 'Item 4',
'e' => 'Item 5',
'f' => 'Item 6',
'g' => 'Item 7',
'h' => 'Item 8',
'i' => 'Item 9',
];
function moveKey($array, $key, $position) {
// Now the array will have [position] => key
$arrayKeyPos = array_keys($array);
// This is so we can have duplicate positions and not overwrite one another
// We're now [key] => position
$arrayKeyPos = array_flip($arrayKeyPos);
// Now this should change the key's position
$arrayKeyPos[$key] = $position;
// Sort them
asort($arrayKeyPos, SORT_NUMERIC);
// At this point the array's keys are in correct order. But there
// is no easy way to attach the values? This is pretty ugly:
$newArray = [];
foreach($arrayKeyPos as $k => $v) {
$newArray[$k] = $array[$k];
}
return $newArray;
}
$testArray = moveKey($testArray, 'c', 99);
// This "sort of" works, it moves it to the 4th, not 3rd, position:
$testArray = moveKey($testArray, 'h', 3);
所以要明确的是,我的问题是,我如何完成上述任务,但第二次调用总是将其移动到第N个位置?
显然,如果索引超出范围(在小于该范围的数组上为-99、99等(,则应该只转到顶部/底部,但对于"3"、"5"等,此代码会失败得很惨。
如果$position
大于数组中的最后一个位置,则将$key
指定的元素移动到数组的末尾,如果小于1:,则将其移动到开头
function moveKey($array, $key, $position) {
$keys = array_keys($array);
$vals = array_values($array);
$pos = array_search($key, $keys);
$new_key = array_splice($keys, $pos, 1);
$new_val = array_splice($vals, $pos, 1);
array_splice($keys, $position-1, 0, $new_key);
array_splice($vals, $position-1, 0, $new_val);
return array_combine($keys, $vals);
}
- 为键和值创建数字索引数组
- 查找键的数字位置
- 从键和值数组中提取找到的键和值阵列
- 将它们拼接到新位置的键和值阵列中
- 将新的键和值数组组合为关联数组
当$position
越界时只返回数组:
function moveKey($array, $key, $position, $wrap=true) {
if($wrap === false && ($position < 1 || $position > count($array)) {
return $array;
}
// rest of code
}
您可以使用unset
将键/值从其原始位置移除,并将slice
与+
组合使用以将该对插入到所需的绝对位置:
function moveKey($array, $key, $position) {
$value = $array[$key];
unset($array[$key]);
return array_slice($array, 0, $position, true) +
[$key => $value] +
array_slice($array, $position, null, true);
}
给定的位置被解释为基于零,因此如下所示:
var_export (moveKey($testArray, "h", 3));
将返回:
array (
'a' => 'Item 1',
'b' => 'Item 2',
'c' => 'Item 3',
'h' => 'Item 8',
'd' => 'Item 4',
'e' => 'Item 5',
'f' => 'Item 6',
'g' => 'Item 7',
'i' => 'Item 9',
)
如果位置参数大于最高索引,则键/值对将位于数组的最后一个位置。
如果位置参数为负数,则位置将从数组末尾向后计数。如果这导致在数组开始之前的位置,则该对将在返回数组的开始处结束。
为什么以零为基础
在PHP中,索引数组是从零开始的。例如,如果采用array_values($array)
,则第一个元素将具有索引0
。或者,如果创建像[1, 2, 3]
这样的索引数组,则值1
将位于索引0
处。因此,如果您要混合使用基于1和基于0的索引号,您将进入大量的-1
和+1
代码,这些代码最终会更加混乱而没有帮助。我强烈建议采用基于0的索引数字。
为什么从负数开始计数
在PHP中,有几个函数提供了这一特性,即位置的负参数被解释为从数组末尾向后偏移。例如array_splice
:
如果偏移是正的,则被移除部分的开始位于距输入阵列的开始的偏移处。如果偏移量为负,那么它从输入数组的末尾开始。
array_slice
和几个字符串函数(如strpos
和strspn
(也是如此。对于explode
的极限自变量,实现了对负值的类似处理。
因此,我认为最好坚持这种行为,并将其视为一种特征。当然,正如评论中所提到的,禁用此功能并使用if ($position < 0) $position = 0;
将任何负偏移转换为0
是很容易的。