如何根据递减标准识别数组中的索引



我有一个数组,它看起来像这样:

[
0=>['v'=> 1, 'c1'=>null , 'c2'=>null , 'c3'=>null],
1=>['v'=> 2, 'c1'=>'A'  , 'c2'=>null , 'c3'=>null],
2=>['v'=> 3, 'c1'=>'A'  , 'c2'=>'B'  , 'c3'=>null],
3=>['v'=> 4, 'c1'=>'A'  , 'c2'=>'B'  , 'c3'=> 'C']
]

c1、c2、c3可以用null或任何字符串独立填充。

我得到了['c1'=>'A','c2'=>'B','c3'=>'C']形式的上下文输入。

如何确定最适合我的输入数组的行的索引。

"最佳";平均值(按降序排列(:

  • 如果上下文中所有三个字符串(c1,c2,c3(都精确匹配和数组返回此索引(在本例中,此规则已经适用并返回3(
  • 如果不存在,则返回适合2个上下文字符串的行的索引,而剩余的一个c*为null(这将适用于类似['c1'=>'A', 'c2'=>'B', 'c3'=>'Z']的上下文并返回2(
  • 如果不存在,则返回行的索引,其中1个字符串匹配,剩下的两个c*s为空(这将适用于类似['c1'=>'A', 'c2'=>'Y', 'c3'=>'Z']的上下文并返回1(
  • 如果不存在,则返回所有三个c*都为null的行的索引(这将适用于类似['c1'=>'X', 'c2'=>'Y', 'c3'=>'Z']的上下文并返回0(

我知道我的数组中可能有一些条目理论上会返回1个以上的索引,但这可以在创建基数组的方式中排除。

我开始了很多尝试,结果都是用了很多嵌套的意大利面条,感觉必须有一种更结构化的方法来实现这一点。

<?php
function find_best($data, $lookfor) {
$bestmatch = false; // what returns if nothing found
$bestscore = -1;
foreach($data as $rowkey => $row) {
$score = 0;
// count how many matches
foreach($lookfor as $k => $v) {
if (isset($row[$k])) { // not null
if ($row[$k] == $v) {
$score++;
} else { // not null but do not match: abort the search, go to next row
$score = -1; 
break;
}
}
}
if ($score > $bestscore) {
if ($score == count($lookfor)) return $rowkey; // best result, return immediately
$bestscore = $score;
$bestmatch = $rowkey;
}
}
return $bestmatch;
}
// Test;
$data =
[
0=>['v'=> 1, 'c1'=>null , 'c2'=>null , 'c3'=>null],
1=>['v'=> 2, 'c1'=>'A'  , 'c2'=>null , 'c3'=>null],
2=>['v'=> 3, 'c1'=>'A'  , 'c2'=>'B'  , 'c3'=>null],
3=>['v'=> 4, 'c1'=>'A'  , 'c2'=>'B'  , 'c3'=> 'C']
];
print find_best($data, ['c1'=>'A','c2'=>'B','c3'=>'C']) . PHP_EOL; // 3
print find_best($data, ['c1'=>'A','c2'=>'B','c3'=>'X']) . PHP_EOL; // 2
print find_best($data, ['c1'=>'A','c2'=>'X','c3'=>'C']) . PHP_EOL; // 1

如果您想编写自己的函数,它可能类似于

$referenceArray = [
0=>['v'=> 1, 'c1'=>null , 'c2'=>null , 'c3'=>null],
1=>['v'=> 2, 'c1'=>'A'  , 'c2'=>null , 'c3'=>null],
2=>['v'=> 3, 'c1'=>'A'  , 'c2'=>'B'  , 'c3'=>null],
3=>['v'=> 4, 'c1'=>'B'  , 'c2'=>'B'  , 'c3'=> 'C']
];
function getBest ( $needle, $reference ) {
$myBestIndex = null;
$myBestMetrix = null;
foreach ( $reference as $index => $values ) {
$currentMetrix = 0;
foreach ($values as $key => $value ) {
if (is_null($value)) continue;
if ($value == $needle[$key]) $currentMetrix++;
else {
$currentMetrix = 0;
break;
}
}
if ($currentMetrix >= ($myBestMetrix ?? $currentMetrix) {
$myBestIndex = $index;
$myBestMetrix = $currentMetrix;
}
}
return $myBestIndex;
}

对于每个搜索用例,您都可以使用array_filter和自己的适当回调。

// $results will contain all of the elements of $values that have ['cX' => 'myValX']
$results = array_filter(
$values, // is your big array in which you want to search
function($value){ // this callback will be called for each element of $values
if($value['c1'] === 'myVal1' AND $value['c2'] === 'myVal2' and $value['c3'] === 'myVal3'){
return true; // to have the match element of $values array to be in the returned array
}
}
);

您必须对整个数组和每行的计数值进行迭代。如果需要,可以将这部分代码封装到自定义函数中。

$array = [
0 => ['v' => 1, 'c1' => null, 'c2' => null, 'c3' => null],
1 => ['v' => 2, 'c1' => 'A', 'c2' => null, 'c3' => null],
2 => ['v' => 3, 'c1' => 'A', 'c2' => 'B', 'c3' => null],
3 => ['v' => 4, 'c1' => 'B', 'c2' => 'B', 'c3' => 'C']
];
$input = ['c1' => 'B', 'c2' => 'B', 'c3' => 'C'];
$best = null;
array_walk($array, function ($val, $key) use (&$best, $input) {
$cur_value = count(array_intersect_assoc($val, $input));
if (is_null($best) || $cur_value > $best['value']) {
$best = [
'index' => $key,
'value' => $cur_value
];
}
});
print_r($best['index']); //output 3

最新更新