如何在有序列表中选择每种类型项目的“至少n”

时间:2014-07-23 16:46:36

标签: php algorithm sorting

我有一个结果列表(请参阅下面的 JSON ),我需要选择前10名。这里他们在json中,但我将json_decoding成数组比如$ coureValues [" BUS1067"] == 117.1

我使用arsort($ courseValues)按顺序获取它们,如下面的 JSON

我需要选择前10名,但我需要强制执行至少4" BUS",至少2" CMP"以及至少1 SAF的约束。因此,例如,如果前10名中没有SAFxxxx,但有6个BUS和2个CMP,我想删除最低得分总线并添加得分最高的SAF。最后,考虑到约束条件,我想要的只是一个前10名的php数组。

JSON

{
    "BUS1067": 117.1,
    "BUS1057": 86.06,
    "BUS1073": 79,
    "BUS1068": 74.08,
    "BUS1077": 74,
    "BUS1001": 71,
    "BUS1066": 68,
    "BUS1076": 67.05,
    "BUS1011": 64,
    "BUS1054": 64,
    "BUS1006": 63,
    "CMP1091": 62,
    "BUS1000": 60,
    "CMP1083": 59,
    "SAF1007": 58,
    "CMP1073": 56,
    "CMP1044": 55,
    "CMP1029": 55,
    "CMP1082": 53,
    "CMP1089": 50,
    "CMP1042": 48,
    "CMP1070": 46,
    "CMP1074": 45,
    "BUS1074": 31,
    "BUS1009": 20,
    "BUS1003": 10,
    "BUS1058": 1.09,
    "BUS1061": 1.07,
    "BUS1056": 1.04,
    "CMP1081": 1.03,
    "SAF1021": 1.01,
    "CMP1064": 0,
    "CMP1039": 0,
    "CMP1047": 0,
    "SAF1045": 0,
    "SAF1047": 0,
    "CMP1063": 0,
    "SAF1020": 0,
    "SAF1043": 0,
    "SAF1032": 0,
    "SAF1038": 0,
    "BUS1075": 0,
    "SAF1002": 0,
    "CMP1037": 0,
    "BUS1040": 0,
    "CMP1078": 0,
    "BUS1013": 0,
    "CMP1080": 0,
    "BUS1002": 0,
    "BUS1048": 0,
    "BUS1071": 0,
    "CMP1072": 0,
    "CMP1088": 0,
    "CMP1084": 0,
    "BUS1031": 0,
    "BUS1055": 0,
    "BUS1063": 0,
    "BUS1072": 0,
    "SAF1013": 0,
    "BUS1012": 0,
    "SAF1006": 0,
    "CMP1049": -20,
    "CMP1048": -20,
    "CMP1050": -20,
    "CMP1075": -20,
    "CMP1038": -925,
    "CMP1041": -929,
    "CMP1079": -933.98
    }

我正在寻找的是一种简单,优雅的方式。我可以“完成它”#34;但是想到的代码是混乱而且不清楚的,似乎有一些通用的算法"或者我应该使用的排序功能。

更新:代码: 根据要求,这是我做一个简单的事情的糟糕代码

<?php

$jsonWeights='{ "BUS1067": 117.1, "BUS1057": 86.06, "BUS1073": 79, "BUS1068": 74.08, "BUS1077": 74, "BUS1001": 71, "BUS1066": 68, "BUS1076": 67.05, "BUS1011": 64, "BUS1054": 64, "BUS1006": 63, "CMP1091": 62, "BUS1000": 60, "CMP1083": 59, "SAF1007": 58, "CMP1073": 56, "CMP1044": 55, "CMP1029": 55, "CMP1082": 53, "CMP1089": 50, "CMP1042": 48, "CMP1070": 46, "CMP1074": 45, "BUS1074": 31, "BUS1009": 20, "BUS1003": 10, "BUS1058": 1.09, "BUS1061": 1.07, "BUS1056": 1.04, "CMP1081": 1.03, "SAF1021": 1.01, "CMP1064": 0, "CMP1039": 0, "CMP1047": 0, "SAF1045": 0, "SAF1047": 0, "CMP1063": 0, "SAF1020": 0, "SAF1043": 0, "SAF1032": 0, "SAF1038": 0, "BUS1075": 0, "SAF1002": 0, "CMP1037": 0, "BUS1040": 0, "CMP1078": 0, "BUS1013": 0, "CMP1080": 0, "BUS1002": 0, "BUS1048": 0, "BUS1071": 0, "CMP1072": 0, "CMP1088": 0, "CMP1084": 0, "BUS1031": 0, "BUS1055": 0, "BUS1063": 0, "BUS1072": 0, "SAF1013": 0, "BUS1012": 0, "SAF1006": 0, "CMP1049": -20, "CMP1048": -20, "CMP1050": -20, "CMP1075": -20, "CMP1038": -925, "CMP1041": -929, "CMP1079": -933.98 }';

$courseValues=json_decode($jsonWeights,true);
arsort($courseValues);

$minRequired=array("BUS"=>4, "CMP"=>2, "SAF"=>1);
$pathLength=10;
$selected=array();

//get top results to satisfy minimum required
foreach ($minRequired as $courseType => $min) {
    foreach($courseValues as $key => $val){
        if(substr($key, 0, 3) == $courseType && $min)
        {
            $selected[$key]=$val;
            $min--;
            if($min==0)
                break;
        }
    }
}


//fill in the remaining with the top results
foreach($courseValues as $k=>$v){
    if(count($selected)<$pathLength)
    {
        if(!array_key_exists($k, $selected))
            $selected[$k]=$v;
    }
    else
        break;
}

arsort($selected);

foreach($selected as $k=>$v)
    echo "$k: $v<br>";

?>

3 个答案:

答案 0 :(得分:0)

$ topten = array_keys(array_slice(arsort($ courseValues),0,10));

好的,抱歉没有彻底阅读这个问题:)

答案 1 :(得分:0)

我首先要创建一个php数组,其中前缀为键,所需的数字如下所示:

$prefixes = array("BUS" => 4, "CMP" => 2, "SAF" => 1);

然后,由于您需要10个元素并且值的总和为7,因此您可以从任何类别中选择3个元素。那么循环应该是这样的:


基本理念:

虽然您没有排序列表中的10个元素:

获取元素。

提取前缀。

如果(前缀数组中存在前缀,且相应的值大于0),     或(剩余前缀值的总和小于所需元素的数量),然后将其添加到结果中。


代码:

$results = array();
foreach ($courseValues as $course => $courseValue) {
    $prefix = substr($course, 0, 3);
    if (isset($prefixes[$prefix]) && $prefixes[$prefix--] >= 0) {
        $results[$course] = $courseValue;
    }
    else if (array_sum($prefixes) < 10 - count($results)) {
        $results[$course] = $courseValue;
    }

    if (count($results) == 10) {
        break;
    }
}

注意:这是假设$ courseValues按$ courseValue

排序

答案 2 :(得分:0)

我的解决方案:

好的,我已经把它归结为一个foreach循环。这是完整的解决方案:

$jsonWeights='{ "BUS1067": 117.1, "BUS1057": 86.06, "BUS1073": 79, "BUS1068": 74.08, "BUS1077": 74, "BUS1001": 71, "BUS1066": 68, "BUS1076": 67.05, "BUS1011": 64, "BUS1054": 64, "BUS1006": 63, "CMP1091": 62, "BUS1000": 60, "CMP1083": 59, "SAF1007": 58, "CMP1073": 56, "CMP1044": 55, "CMP1029": 55, "CMP1082": 53, "CMP1089": 50, "CMP1042": 48, "CMP1070": 46, "CMP1074": 45, "BUS1074": 31, "BUS1009": 20, "BUS1003": 10, "BUS1058": 1.09, "BUS1061": 1.07, "BUS1056": 1.04, "CMP1081": 1.03, "SAF1021": 1.01, "CMP1064": 0, "CMP1039": 0, "CMP1047": 0, "SAF1045": 0, "SAF1047": 0, "CMP1063": 0, "SAF1020": 0, "SAF1043": 0, "SAF1032": 0, "SAF1038": 0, "BUS1075": 0, "SAF1002": 0, "CMP1037": 0, "BUS1040": 0, "CMP1078": 0, "BUS1013": 0, "CMP1080": 0, "BUS1002": 0, "BUS1048": 0, "BUS1071": 0, "CMP1072": 0, "CMP1088": 0, "CMP1084": 0, "BUS1031": 0, "BUS1055": 0, "BUS1063": 0, "BUS1072": 0, "SAF1013": 0, "BUS1012": 0, "SAF1006": 0, "CMP1049": -20, "CMP1048": -20, "CMP1050": -20, "CMP1075": -20, "CMP1038": -925, "CMP1041": -929, "CMP1079": -933.98 }';
$courseValues=json_decode($jsonWeights,true);
arsort($courseValues);

$required=array("BUS"=>4, "CMP"=>2, "SAF"=>1,"Total" => 10);
$selected=array();
foreach($required as $type => $min)
    foreach($courseValues as $key => $val)
        if(count($selected)<$required['Total'] 
        &&($type=='Total'||(substr($key,0,3)==$type && $min-->0)))
            $selected[$key]=$val;

如果有人有更好的想法,我会把它打开