Did something similar to this on a personal project, but in php code. If you wish to port to c#, feel free.
This code takes into account the possibility of multiple combinations being the same, so the return value will be an array of x best results.
NOTE: This is taking in to account that any item can be used 0 or 1 times in each result
<?php $products = [ ['id' => 1, 'price' => 3.00, 'energy' => 200], ['id' => 2, 'price' => 14.10, 'energy' => 3200], ['id' => 3, 'price' => 2.66, 'energy' => 300], ['id' => 4, 'price' => 5.00, 'energy' => 450], ['id' => 5, 'price' => 6.23, 'energy' => 667], ['id' => 6, 'price' => 7.00, 'energy' => 1200] ]; function genCombinations($values, $count = 0) { // Figure out how many combinations are possible: $comboCount = pow(count($values) , $count); $r = []; // Iterate and add to array for ($i = 0; $i < $comboCount; $i++){ $r[] = getCombination($values, $count, $i); } return $r; } // State-based way of generating combinations: function getCombination($values, $count, $index) { $result = []; for ($i = 0; $i < $count; $i++) { // Figure out where in the array to start from, given the external state and the internal loop state $pos = $index % count($values); // Append and continue $result[] = $values[$pos]; $index = ($index - $pos) / count($values); } return $result; } //maximize energy for given price function getBestProductCombinations($products,$price_limit){ //find all combinations where each product is either selected or not - true or false $combos = genCombinations([true,false],count($products)); $results = []; foreach($combos as $combo){ //loop through each combination and get a result $sum_price = 0;$items = [];$sum_energy = 0; foreach($combo as $i => $o){ //loop through the array of true/false values determining if an item is on or off if($o){ //if on, add item to result $sum_price += $products[$i]['price']; $sum_energy += $products[$i]['energy']; $items[] = $products[$i]; } } if($sum_price <= $price_limit){ //if sum of result is within the price limit, add to the results array $results[] = [ 'items' => $items, 'price' => $sum_price, 'energy' => $sum_energy ]; } } $best = $results[0];$ra = [$best]; foreach($results as $k => $result){ if($k === 0){continue;}//skip first iteration as it was set above //check if the energy is higher than the best, or if equal, check if the price is better if($result['energy'] > $best['energy'] || ($result['energy'] === $best['energy'] && $result['price'] < $best['price'])){ //reset best to the current result, reset return array $best = $result; $ra = [$best]; }else if($result['energy'] === $best['energy']){ //current result is the same as best, add it to the return array $ra[] = $result; } } return $ra; } echo '<pre>'.json_encode(getBestProductCombinations($products,10),JSON_PRETTY_PRINT).'</pre>';
Which then would give you:
[ { "items": [ { "id": 3, "price": 2.66, "energy": 300 }, { "id": 6, "price": 7, "energy": 1200 } ], "price": 9.66, "energy": 1500 } ]