【问题标题】:Filter 3-level array using an associative array defining the numeric values which must be exceeded使用定义必须超过的数值的关联数组过滤 3 级数组
【发布时间】:2017-01-09 18:32:42
【问题描述】:

我有一个包含技能 ID 及其合格分数/分数的关联数组。例如:

Array
(
    [3] => 2 // skill => eligible marks
    [63] => 6
    [128] => 3
)

我有一个以学生 ID 作为第一级键的多维数组。第二级包含索引子数组,将技能 ID 和标记/分数表示为 2 元素关联数组。

Array
(
    [22] => Array
        (
            [0] => Array
                (
                    [skill_id] => 3
                    [gd_score] => 4
                )

            [1] => Array
                (
                    [skill_id] => 128
                    [gd_score] => 6
                )

        )

    [23] => Array
        (
            [0] => Array
                (
                    [skill_id] => 128
                    [gd_score] => 3
                )

        )

    [24] => Array
        (
            [0] => Array
                (
                    [skill_id] => 3
                    [gd_score] => 7
                )

            [1] => Array
                (
                    [skill_id] => 63
                    [gd_score] => 8
                )

            [2] => Array
                (
                    [skill_id] => 128
                    [gd_score] => 9
                )

        )

)

我想根据第一个数组中的值过滤学生。

我想让所有学生:

  • 技能 3 分数大于 2 并且
  • 技能 63 分数大于 6 并且
  • 技能 128 分大于 3。

如果满足所有条件,则返回学生 ID。因为只有学生 24 满足所有要求,所以输出应该是 [24]——一个包含单个元素的数组。

【问题讨论】:

  • 显示如何查看预期输出以获得快速帮助
  • results 将是学生证,在我上面的问题中答案是 24,因为它满足所有条件。

标签: php arrays multidimensional-array filtering multiple-conditions


【解决方案1】:

使用以下方法:

$marks = array
(
    3 => 2, // skill => eligible marks
    63 => 6,
    128 => 3
);

// $arr is your initial array of student data
$student_ids = [];
$marks_count = count($marks);
foreach ($arr as $k => $items) {
    // if number of marks coincide
    if ($marks_count != count($items)) {
        continue;
    }
    
    foreach ($items as $item) {
        if (!isset($marks[$item['skill_id']]) 
            || $marks[$item['skill_id']] >= $item['gd_score']
        ) {
            continue 2;
        }
    }
    $student_ids[] = $k;
}

print_r($student_ids);

输出:

Array
(
    [0] => 24
)

测试链接:https://eval.in/private/10a7add53b1378

【讨论】:

    【解决方案2】:

    感谢@RomanPerekhrest 提供了一种高效的嵌套循环方法,该方法具有条件早期continues。我确实认为在某些情况下对数据质量的假设会造成麻烦,但我会避免发明代码污染测试用例。

    无论如何,我认为我以前不需要尝试过array_udiff_assoc(),所以这是一个很好的机会。

    我的 sn-p 将关联过滤掉所有缺少所需测试或实际分数不高于合格分数的第一级条目。

    我的 sn-p 并非旨在超越 Roman 的嵌套循环,我没有对其进行基准测试。我只是想提供一种简洁的函数式方法。

    样本数据:

    $criteria = [3 => 2, 63 => 6, 128 => 3];
    
    $allScores = [
        22 => [
            ['skill_id' => 3, 'gd_score' => 4],
            ['skill_id' => 999, 'gd_score' => 9],
            ['skill_id' => 128, 'gd_score' => 7],
        ],
        23 => [
            ['skill_id' => 128, 'gd_score' => 3],
        ],
        24 => [
            ['skill_id' => 63, 'gd_score' => 8],
            ['skill_id' => 3, 'gd_score' => 7],
            ['skill_id' => 128, 'gd_score' => 9],
        ],
        25 => [
            ['skill_id' => 3, 'gd_score' => 7],
            ['skill_id' => 63, 'gd_score' => 8],
            ['skill_id' => 128, 'gd_score' => 1],
        ],
        26 => [
            ['skill_id' => 3, 'gd_score' => 2],
            ['skill_id' => 63, 'gd_score' => 6],
            ['skill_id' => 128, 'gd_score' => 3],
        ],
    ];
    

    代码:(Demo)

    var_export(
        array_keys(
            array_filter(
                $allScores,
                fn($scores) => !array_udiff_assoc(
                    $criteria,
                    array_column($scores, 'gd_score', 'skill_id'),
                    fn($cVal, $sVal) => $cVal >= $sVal
                )
            )
        )
    );
    

    输出:

    array (
      0 => 24,
    )
    

    如果我要制作一个嵌套循环脚本(假设技能分数不能为负数),我会这样构建它:(Demo)

    $result = [];
    foreach ($allScores as $key => $scores) {
        $skillScores = array_column($scores, 'gd_score', 'skill_id');
        foreach ($criteria as $id => $toBeat) {
            if (($skillScores[$id] ?? 0) <= $toBeat) {
                continue 2;
            }
        }
        $result[] = $key;
    }
    var_export($result);
    

    与早期的功能性 sn-p 一样,此 sn-p 提供相同的输出,并允许可选技能数据存在而不会破坏业务规则。使用array_column() 创建查找数组可避免循环遍历每个规则的分数子数组。

    第二个 sn-p 可能会优于第一个,但如果确实如此,我预计差异不会非常明显

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多