我想将数组的每个元素相互比较。
$char=array();
for($i=0;$i<=10;$i++)
{
$char[$i]=rand(0,35);
}
我想比较 $char 数组的每个元素。如果有任何重复的值比它应该改变值并选择另一个在数组中应该是唯一的随机值..
在此特定示例中,可能值的范围非常小,最好以另一种方式执行此操作:
$allPossible = range(0, 35);
shuffle($allPossible);
// Guaranteed exactly 10 unique numbers in the range [0, 35]
$char = array_slice($allPossible, 0, 10);
或使用等效版本array_rand
:
$allPossible = range(0, 35);
$char = array_rand(array_flip($allPossible), 10);
如果值的范围更大,那么这种方法将非常浪费,您应该在每次迭代时检查唯一性:
$char = array();
for ($i = 0; $i < 10; ++$i) {
$value = null;
// Try random numbers until you find one that does not already exist
while($value === null || in_array($value, $char)) {
$value = rand(0, 35);
}
$char[] = $value;
}
但是,这是一种概率方法,可能需要很长时间才能完成,具体取决于输出的rand
结果(如果您想要的值的数量接近所有可能值的数量,这将特别糟糕)。
此外,如果您要选择的值的数量很大(比如说超过 50 个左右),那么in_array
可能会成为瓶颈。在这种情况下,使用数组键而不是值来检查唯一性应该更快,因为搜索键的存在是常数时间而不是线性时间:
$char = array();
for ($i = 0; $i < 100; ++$i) {
$value = null;
// Try random numbers until you find one that does not already exist
while($value === null || array_key_exists($char, $value)) {
$value = rand(0, 1000);
}
$char[$value] = $value;
}
$char = array_values($char); // reindex keys to start from 0
要更改随机值的任何重复值,您应该循环遍历数组两次:
$cont= 0;
foreach($char as $c){
foreach($char as $d){
if($c == $d){
//updating the value
$char[$cont] = rand(0,35);
}
}
$cont++;
}
但我不知道随机值是否也可以重复。在那种情况下,事情就不会那么简单了。
<?php
function uniqueRand($n, $min = 0, $max = null)
{
if($max === null)
$max = getrandmax();
$array = range($min, $max);
$return = array();
$keys = array_rand($array, $n);
foreach($keys as $key)
$return[] = $array[$key];
return $return;
}
?>
此函数生成一个大小为 $n 的数组,您可以像 rand 一样设置最小值和最大值。
所以你可以像使用它一样
uniqueRand(10, 0, 35);
array_count_values()
首先在$char
阵列上使用。
之后,您可以循环所有大于 1 的条目并将它们随机化。您必须不断检查,直到所有计数都为 1。因为即使是随机的也可能再次复制。
我建议使用两个选项来制作随机数组:
<?php
$questions = array(1, 2, 3, 4, 5, ..., 34, 35);
$questions = shuffle($questions);
?>
之后,您选择前 10 个元素。
您可以尝试使用此代码替换任何重复的值。
for ($i = 0; $i < count($char); $i++) {
for ($n = 0; $n < count($char); $n++) {
if($char[$i] == $char[$n]){
$char[$i] = rand(0,35);
}
}
}
该函数array_unique()
从数组中获取所有唯一值,以它们的第一次出现为键。
该函数array_diff()
允许从一个数组中删除另一个数组中的值。
根据您需要(或不拥有)键控结果或保留键的顺序,您需要执行多个步骤。通常它的工作原理与我在以下段落中概述的一样(使用 PHP 代码示例):
在一个数组中,您拥有独特N
的元素。Nu
$N = array(...);
$Nu = array_unique($N);
r
然后替换重复项所需的随机元素数是 的计数N
减去 的计数Nu
。由于计数N
通常是一个有用的值,我还将它分配给nc
:
$nc = count($N);
$r = $nc - count($Nu);
这使得r
整数范围从0
到count(N) - 1
:
0 : no duplicate values / all values are unique
1 : one duplicate value / all but one value are unique
...
count(N) - 1 : all duplicate values / no unique value
因此,如果您需要零随机值 ( $r === 0
),则输入$N
就是结果。这个边界条件是第二个最简单的结果(第一个简单的结果是一个没有成员的输入数组)。
对于所有其他情况,您需要r
随机唯一值。在您的问题中,您从 0 写到 35。但这不可能是完整的故事。假设您的输入数组有 36 个重复值,从 0 到 35 范围内的每个数字都重复一次。再次将 0 到 35 范围内的随机数添加到数组将再次创建重复项 - 保证。
相反,我已经阅读了您的问题,即您只是在寻找尚不属于输入数组的唯一值。
因此,您不仅需要r
随机值 ( Nr
),而且它们也不能属于N
或Nu
到目前为止。
要实现这一点,您只需要创建count(N)
唯一值,Nu
从这些值中删除唯一值以确保没有重复的值在Nu
. 由于这是理论上的最大值而不是所需的确切数字,因此该数组用于从以下位置获取精确r
元素的切片:
$Nr = array_slice(array_diff(range(0, $nc - 1), $Nu), 0, $r);
如果您还希望按range(0, $nc - 1)
顺序添加这些新值,则可以执行以下操作:
shuffle($Nr);
这应该将您在问题中似乎要求的随机性带回答案中。
现在为您留下了原始数组的独特部分$Nu
和. 合并这两个数组将为您提供一个忽略键 => 值关系的结果数组(该数组是重新索引):r
$Nr
array_merge($Nu, $Nr);
例如,对于示例array(3, 4, 2, 1, 4, 0, 5, 0, 3, 5)
,$N
它给出的结果是:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 0
[5] => 5
[6] => 7
[7] => 9
[8] => 6
[9] => 8
)
如您所见,所有唯一值 (0-5) 都在开头,然后是新值 (6-9)。不保留原始密钥,例如 value 的密钥5
最初是6
,现在是5
。
没有保留关系或键 => 值,因为array_merge()
它会重新索引数字键。此外,在键中的唯一数字旁边Nr
也需要在数组中是唯一的。因此,对于添加到唯一现有数字的每个新数字,都需要使用一个密钥,该密钥是重复数字的密钥。为了获得所有重复数字的键,原始数组中的键集合被所有重复数字匹配的键集合减少(“唯一数组”中的键$Nu
):
$Kr = array_keys(array_diff_assoc($N, $Nu));
$Nr
现在可以使用这些键来键入现有结果。PHP 中为数组设置所有键的函数是使用该函数array_combine()
:
$Nr = array_combine($Kr, $Nr);
这允许通过使用数组联合运算符 ( +
)获得保留键 => 值关系的结果:
$Nu + $Nr;
例如,对于$N
上一个示例,它给出的结果是:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[5] => 0
[6] => 5
[4] => 8
[7] => 6
[8] => 9
[9] => 7
)
正如您现在所看到的,5
它的键值以及在原始数组中具有键的值以及现在在输出中而不是前面示例中的键6
的值都被保留了。0
5
4
但是,由于现在已为原始值的第一次出现保留了键,因此顺序仍然发生了变化:首先是所有以前唯一的值,然后是所有新值。但是,您可能希望在适当的位置添加新值。为此,您需要获取新值的原始键的顺序。这可以通过按键映射顺序并array_multisort()
根据该顺序进行排序来完成。
因为这需要通过参数传递返回值,所以这需要额外的临时变量,我选择引入以字母V开头的变量:
// the original array defines the order of keys:
$orderMap = array_flip(array_keys($N));
// define the sort order for the result with keys preserved
$Vt = $Nu + $Nr;
$order = array();
foreach ($Vt as $key => $value) {
$order[] = $orderMap[$key];
}
然后排序完成(这里使用保留键):
// sort an array by the defined order, preserve keys
$Vk = array_keys($Vt);
array_multisort($order, $Vt, $Vk);
结果是:
array_combine($Vk, $Vt);
再次使用上面的示例值:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 7
[5] => 0
[6] => 5
[7] => 8
[8] => 6
[9] => 9
)
此示例输出很好地显示了键从 0 到 9 排序,因为它们在输入数组中很好。例如,与之前的输出相比,您可以看到第一个添加的值7
(keyed 4
) 位于第 5 位 - 与4
原始数组中键入的值相同。密钥的顺序也已获得。
如果这是您努力争取的结果,您也可以通过迭代原始数组键来缩短此步骤的路径,如果这些键中的每一个都不是任何重复值的第一个值,您可以从新值中弹出数组代替:
$result = array();
foreach ($N as $key => $value) {
$result[$key] = array_key_exists($key, $Nu) ? $Nu[$key] : array_pop($Nr);
}
再次使用示例数组值的结果(与以前的不同,因为$Nr
被打乱了:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 7
[5] => 0
[6] => 5
[7] => 8
[8] => 9
[9] => 6
)
最后,这可能是回答您问题的最简单方法。希望这可以帮助您回答问题。请记住以下几点:
array_unique()
在这里帮助你。array_diff()
在这里帮助你。就像在这个例子中一样:
// original array
$array = array(3, 4, 2, 1, 4, 0, 5, 0, 3, 5);
// obtain unique values (1.)
$unique = array_unique($array);
// obtain new unique values (2.)
$new = range(0, count($array) - 1);
$new = array_diff($new, $unique);
shuffle($new);
// process original array (3.)
foreach ($array as $key => &$value) {
if (array_key_exists($key, $unique)) {
continue;
}
$value = array_pop($new);
}
unset($value, $new);
// result in $array:
print_r($array);
然后(因为 示例shuffle($new)
)输出:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 9
[5] => 0
[6] => 5
[7] => 8
[8] => 7
[9] => 6
)