[英]How to compare every element of array with one another?
我想将数组的每个元素相互比较。
$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手册页的rand()那里获取了这段代码
<?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);
首先在$char
数组上使用array_count_values()
。
之后,您可以循环所有大于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)
来range(0, $nc - 1)
添加这些新值,则可以执行以下操作:
shuffle($Nr);
这应该将您似乎在问题中要求的随机性带回到答案中。
现在,您将剩下原始数组$Nu
的唯一部分以及$Nr
r
新值。 合并这两个数组将为您提供一个结果数组,该数组将忽略key => value关系(该数组是重新索引的):
array_merge($Nu, $Nr);
例如,使用$N
的示例array(3, 4, 2, 1, 4, 0, 5, 0, 3, 5)
,得到的结果是:
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)。 原始键不保留,例如,值5
的键原为6
,现在为5
。
由于array_merge()
,关系或键=>的值未保留,它会重新索引数字键。 同样,在Nr
键中唯一编号旁边也需要在数组中唯一。 因此,对于添加到不确定现有数字中的每个新数字,都需要使用一个密钥,该密钥是重复数字的密钥。 为了获得所有重复编号的键,对于重复编号的匹配项,将原始数组中的键集减少为all的键集(“唯一数组” $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
,而不是前面的示例中的键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
(键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
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.