一个php的面试题,大家看看
$listData = [
'111' => ['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
...
];
定义一个函数,传入$listData
如果111
里面的元素,和 222/333/444... 里面的元素有重复,返回false
如果222
里面的元素,和 111/333/444... 里面的元素有重复,返回false
如果333
里面的元素,和 111/222/444... 里面的元素有重复,返回false
如果 ...允许 111/222/333/444 自己里面的元素重复,返回true
其他情况返回true
已知:
$listData长度未知
111/222/333/444... 的长度未知
111/222/333/444... 里的元素为字符串和数字
我自己实现了一下,感觉算法很糟,请问有没有其他方法
function test ($array) {
$tempValueList = [];
foreach ($array as $key => $valueList) {
foreach ($valueList as $value) {
$tempValueList[] = $key . '~' . $value;
}
}
$result = true;
foreach ($array as $key => $valueList) {
foreach ($valueList as $value) {
foreach ($tempValueList as $_value) {
$pos = strpos($_value, '~');
$_key = substr($_value, 0, $pos);
$_val = substr($_value, $pos + 1);
if ($key == $_key) {
continue;
}
if ($_val == $value) {
$result = false;
break 3;
}
}
}
}
return $result;
}
回复内容:
$listData = [
'111' => ['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
...
];
定义一个函数,传入$listData
如果111
里面的元素,和 222/333/444... 里面的元素有重复,返回false
如果222
里面的元素,和 111/333/444... 里面的元素有重复,返回false
如果333
里面的元素,和 111/222/444... 里面的元素有重复,返回false
如果 ...允许 111/222/333/444 自己里面的元素重复,返回true
其他情况返回true
已知:
$listData长度未知
111/222/333/444... 的长度未知
111/222/333/444... 里的元素为字符串和数字
我自己实现了一下,感觉算法很糟,请问有没有其他方法
function test ($array) {
$tempValueList = [];
foreach ($array as $key => $valueList) {
foreach ($valueList as $value) {
$tempValueList[] = $key . '~' . $value;
}
}
$result = true;
foreach ($array as $key => $valueList) {
foreach ($valueList as $value) {
foreach ($tempValueList as $_value) {
$pos = strpos($_value, '~');
$_key = substr($_value, 0, $pos);
$_val = substr($_value, $pos + 1);
if ($key == $_key) {
continue;
}
if ($_val == $value) {
$result = false;
break 3;
}
}
}
}
return $result;
}
看了看,之前的那俩答案都是不能用的。LZ真是苦命。。
我对子数组的定义是像 ['a', 'b', 'c', 'a'] 这样的单个数组。
我的答案:
$result = array();
foreach ($listData as $line) {
//子数组内部去重,再组装回原来的格式
$result[] = array_unique($line);
}
//子数组先去重再合并的结果数量 和 先合并子数组再去重的结果数量 做比较。
//如果是相同的,意味着不存在跨子数组的重复,只存在子数组内部重复,所以`True`
var_dump(count(array_merge(...$result)) === count(array_unique(array_merge(...$listData))));
我这个答案调用系统函数次数比较多,看起来简洁一些,但是PHP array_xxx 这类函数很大一部分性能是不具备优势的,如果不用这些函数,能相对程度提高运行效率。
目前, @springhack 的效率是最高的。而且在各种情形下都能保持最高效率。
方便理解的辅助参考信息:
原始数据:
$listData = [
'111' => ['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j']
];
然后 $result 最终是这样的:
$listData = [
'111' => ['a', 'b', 'c'],
'222' => ['d', 'e', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j']
];
子数组先去重再合并的结果
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
[5] => f
[6] => b
[7] => g
[8] => h
[9] => i
[10] => j
)
用于和上面进行数量(数组元素数量)比较的,所谓的“先合并子数组再去重的结果”:
Array
(
[0] => a
[1] => b
[2] => c
[4] => d
[5] => e
[6] => f
[9] => g
[10] => h
[11] => i
[12] => j
)
循环一次,当前元素和其它所有元素求交集,代码如下:
function isExistsInOther($data)
{
$temp = [];
$isExists = true;
foreach ($data as $key=>$value) {
$temp = $data;
unset($temp[$key]);
if(!$isExists) break;
@array_walk($temp,function($v,$k) use($value,&$isExists){
if($isExists) {
$intersect = array_intersect($v,$value);
if(!empty($intersect)) {
$isExists = false;
}
}
});
}
return $isExists;
}
$listData = [
'111' => ['a', 'k', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'e'],
'444' => ['i', 'j']
];
$result = isExistsInOther($listData);
var_dump($result);
//true 无交集
//false 有交集
/**
* [checkRepeat 检查每个key的数组值是否与其它的有重复值]
* @param [type] $listData [检查的数组]
* @return [type] [array]
*/
function checkRepeat($listData) {
foreach($listData as $key =>$val) {
$check_arr = $listData;
// 删除当前key
unset($check_arr[$key]);
// 合并删除后的数组
$check_arr = array_merge(...$check_arr);
// 判断是否存在交集
$rs[$key] = count(array_intersect($val, $check_arr)) > 0 ? false : true ;
}
return $rs;
}
$listData = [
'111' => ['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
];
$rs = checkRepeat($listData);
function check($arr)
{
$chk = [];
foreach ($arr as $k => $v)
foreach ($v as $i)
{
if (isset($chk[$i] && $chk[$i] != $k)
return false;
$chk[$i] = $k;
}
return true;
}
爪机码字,应该是效率最高的,自己调试下。
既然上面都给了答案,我给你补充一下,多维数组去重
/**
* 多维数组去重
* @param array
* @return array
*/
function super_unique($array)
{
$result = array_map("unserialize", array_unique(array_map("serialize", $array)));
foreach ($result as $key => $value)
{
if ( is_array($value) ) {
$result[$key] = super_unique($value);
}
}
return $result;
}
多维数组去重
$listData = array_values($listData);
foreach ($listData as $k => $v) {
foreach ($listData as $n => $m) {
if($k == $n) continue;
if(array_intersect($v , $m)){
echo $k.$n.'false
';
}
else{
echo $k.$n.'true
';
}
}
}
我的答案(原理:循环求交集):
['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f','b'],
'333' => ['g', 'h','c'],
'444' => ['i', 'j']
];
function jiaoji($array){
$listData = array_values($array);
$list = [];
for ($i = 0; $i
能不能这样理解 只要这个数组里面的值相互之间有交集 那就返回false 。。。
array_intersect()函数好像可以用。但是问题就是在于将一个数组里面的值变成小数组传值。
['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
...
];
function getArr($listData){
$isUnsetFirstKey = false;
$len = count($listData);
if($len $val) {
$arr = array_unique($val);
$newarr = array_merge($firstArr,$arr);
if(count($newarr) != count(array_unique($newarr))){
$isUnsetFirstKey = true;
unset($newList[$key]);
echo $key . "
";
}
}
if($isUnsetFirstKey) echo $firstKey . "
";
getArr($newList);
}
getArr($listData);
?>
我的答案,看看吧,很厉害的
一维数组和二维数组类似, 在内部做判断, 下面是二维数组的方法, 一维数组略过
比较数组合并之前和之后(之后取unique)的数组长度
function check_repeat($arr){
$after_arr = [];
// 对比自身
foreach($arr as $index => $value){
$arr[$index] = $after_arr = array_unique($value);
if(count($value) !== count($after_arr)){
return true;
}
}
// 对比其他
$temp = array_shift($arr);
$cnt = count($temp);
foreach ($arr as $index => $value) {
$cnt += count($value);
$temp = array_merge($temp, $value);
}
return $cnt !== count(array_unique($temp)) ? true : false;
}
$listData = [
'111' => ['a', 'b', 'c',],
'222' => ['d', 'e', 'f',],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
];
var_dump(check_repeat($listData));
function test($listData) {
$result = array_map('array_unique', $listData);
foreach ($result as $key => $value) {
$keys = array_values(array_diff(array_keys($result),[$key]));
for($i = 0; $i
['a', 'b', 'c', 'a'],
'222' => ['d', 'e', 'f', 'f', 'b'],
'333' => ['g', 'h'],
'444' => ['i', 'j'],
];
$temp = array();
foreach ($listData as $key => $xxx) {
foreach ($xxx as $value) {
if (in_array($value, $temp)) {
echo $value.' from '.$key.' is in array';
exit();
}
}
$temp = array_merge($temp, $xxx);
}
echo 'You should get a True!';
没几行,满足需求。
还原之前那个
shiji 的答案
先array_pop,取出最后一项。再取items数组的并集。if并集与最后一项有交集则返回true(表重复)。循环执行。
根据 @大呜 的算法改良了一下。
function checkRepeat2($listData)
{
$check_arr = $listData;
foreach ($listData as $key => $val) {
//之前比较过的key无需再比较
unset($check_arr[$key]);
if ($check_arr) {
// 合并删除后的数组,判断是否存在交集
//As PHP 5.6 you can use array_merge + "splat" operator to reduce a bidimensonal array to a simple array:
if (array_intersect($val, array_merge(...$check_arr))) {
return false;
}
}
}
return true;
}
不知道是不是这样:
$new_arr = [];
foreach ($listData as $key => $value) {
foreach ($value as $k => $v) {
$kv = $k . $v;
if (in_array($kv, $new_arr)) {
echo '有重复';exit;
} else {
$new_arr[] = $kv;
}
}
}
上一篇: java怎么拿到PHP的数据
下一篇: IIS上 php到底要什么权限