Как я могу выбрать "по крайней мере n" каждого типа элемента в упорядоченном списке

Вопрос:

У меня есть список результатов (см. JSON ниже), и мне нужно выбрать топ-10. Здесь они находятся в json, но я json_decoding их в массив вроде $ coureValues [«BUS1067»] == 117.1

Я использую arsort ($ courseValues), чтобы получить их, как JSON ниже.

Мне нужно выбрать топ-10, но мне нужно обеспечить ограничение по крайней мере на 4 «BUS», как минимум 2 «CMP» и по крайней мере 1 SAF. Например, если нет SAFxxxx в топ-10, но есть 6 BUS и 2 CMP, я хочу удалить самую низкую BUS BUS и добавить SAF с наивысшей оценкой. В конце концов, все, что я хочу, это php-массив с топ-10 с учетом ограничений.

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
}

то, что я ищу, — это простой и элегантный способ сделать это. Я мог бы «сделать это», но код, который приходит на ум, беспорядочен и неясен, и кажется, что есть какой-то общий «алгоритм» или функция сортировки, которую я должен использовать.

UPDATE: CODE: в соответствии с запросом, вот мой ужасный код, чтобы сделать простую вещь

<?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>";

?>

Лучший ответ:

МОЕ РЕШЕНИЕ:

Хорошо, я добрался до одного цикла 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;

Я оставлю его открытым, если у кого-то есть лучшая идея

Ответ №1

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

хорошо, извините за то, что не прочитал вопрос полностью 🙂

Ответ №2

Я бы начал с создания 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

Оцените статью
TechArks.Ru
Добавить комментарий