PHP中的array_unique函数
首先
你好。
我是y-encore,是第一年的服务器端工程师,在格伦吉2017年Advent日历上发表的12月8日的文章。今天我想谈谈我们在开发中使用的PHP的array_unique函数。(很抱歉,我将正题的内容改变了)
array_unique是什么?
有关内容请点击这里。
http://php.net/manual/ja/function.array-unique.php
使用PHP的用户可能会知道,这是一个用于删除数组中重复值的函数。
当我们现实中举个例子时,
$testArray = [
'one' => 1,
'two' => 1,
'three' => 2,
'four' => 1,
'five' => 3,
];
print_r(array_unique($testArray));
Array
(
[one] => 1
[three] => 2
[five] => 3
)
没有关系没有key。即使数字和字符串混合,也可以删除转换为字符串后相等的项。
$testArray = [
1,
'1',
2,
1,
'3',
];
print_r(array_unique($testArray));
Array
(
[0] => 1
[2] => 2
[4] => 3
)
想在多维数组中应用。
有时候我们想要以关联数组的形式获取数据,并创建一个整理后的数组,然后从中删除重复的数据。
在之前的php.net说明中,
注意:请注意,array_unique() 不适用于多维数组。
然而,当你搜索”array_unique 多维数组”时,你会发现如果在array_unique的第二个参数sort_flags中指定SORT_REGULAR,似乎会得到良好的结果。
$testArray = [
'one' => [
'first' => 1,
'second' => 2,
],
'two' => [
'first' => 1,
'second' => 2,
],
'three' => [
'first' => 0,
'second' => 2,
],
'four' => [
'first' => 1,
'second' => 2,
],
];
print_r(array_unique($testArray, SORT_REGULAR));
Array
(
[one] => Array
(
[first] => 1
[second] => 2
)
[three] => Array
(
[first] => 0
[second] => 2
)
)
我明白了,看起来重复数据被巧妙地删除了。
有时候会出现不顺利的情况
php_unique的实现首先对数组进行一次排序,然后去除重复的元素以进行重复判断。
之前提到的sort_flags是指定排序时要匹配的数据类型,如果是SORT_REGULAR,则进行比较和排序时不进行特殊的类型转换。
由于需要进行排序才能判断重复,如果排序时比较不成功的元素包含在内,则array_unique的结果将不稳定。
我們使用SORT_REGULAR來對多維數組進行array_unique操作,但正如這篇文章所指出的,當數字和字符串混合時,可能會表現出不穩定的行為。
在某些情况下,当想要对具有不同结构的关联数组进行重复检查时,由于无法很好地比较元素,array_unique的结果将变得不稳定。让我们举一个具体的例子来说明。
首先,我们将创建一个方法,用于创建无法进行简单比较的关联数组。
function createTestArray($keyName) {
return [
'one' => 1,
'two' => 2,
$keyName => 3,
];
}
echo '(three < san) ' . (createTestArray('three') < createTestArray('san') ? 'true' : 'false');
echo '(three > san) ' . (createTestArray('three') > createTestArray('san') ? 'true' : 'false');
echo '(three === san) ' . (createTestArray('three') === createTestArray('san') ? 'true' : 'false');
echo '(three === three) ' . (createTestArray('three') === createTestArray('three') ? 'true' : 'false');
echo '(san === san) ' . (createTestArray('san') === createTestArray('san') ? 'true' : 'false');
(three < san) : false
(three > san) : false
(three === san) : false
(three === three) : true
(san === san) : true
在具有不同结构的关联数组之间进行大小比较都会得到false,简单的比较不能进行排序。我们尝试对包含这种关联数组作为列表的数组使用array_unique。
$keyNameList = [
'three',
'san',
];
$testArrayList = [];
for ($i = 0; $i < 30; $i++) {
$testArrayList[] = createTestArray($keyNameList[rand(0, 1)]);
}
print_r(array_unique($testArrayList, SORT_REGULAR));
Array
(
[0] => Array
(
[one] => 1
[two] => 2
[san] => 3
)
[1] => Array
(
[one] => 1
[two] => 2
[san] => 3
)
[3] => Array
(
[one] => 1
[two] => 2
[three] => 3
)
[18] => Array
(
[one] => 1
[two] => 2
[three] => 3
)
)
有一些确实消失了,但仍然可以确认重复的元素仍然存在。
不使用array_unique来删除重复元素
在去除具有不同结构的关联数组元素的重复时,我认为不使用array_unique并自己实现是安全的。虽然计算成本会增加,但你可以使用foreach和in_array相对容易地编写它。
function myArrayUnique($array) {
$uniqueArray = [];
foreach($array as $key => $value) {
if (!in_array($value, $uniqueArray)) {
$uniqueArray[$key] = $value;
}
}
return $uniqueArray;
}
此外,如果不需要键,也可以使用array_reduce和in_array进行编写。由于在去除重复项的情况下通常不需要键值,因此这种方式可能更加优雅。
$uniqueArray = array_reduce($array, function($carry, $item) {
if (!in_array($item, $carry)) {
$carry[] = $item;
}
return $carry;
}, []);
最后
非常感谢阅读至此!格伦吉的圣诞倒数日还将继续,敬请期待并多多支持。
[前日]12/7日 raitome: 尝试使用最新版的Spine
https://qiita.com/raitome/items/5ae1fce0bb4fc68fc796
Unity的负荷削减,从12月9日开始!