我有以下代码来获取满足requiredNumbers标准的最便宜对象列表。此对象列表的长度可以从1到 maxLength ,即可以允许重复的对象的1到 maxLength 的组合。现在,这将遍历整个组合列表(IEnumerable of IEnumerable of OBJECT)罚款直到maxLength = 9并在之后用“System.OutOfMemoryException”打破
t1.Concat(new OBJECT[] { t2 }
我尝试了另一种解决方法(在代码注释中提到),但这似乎有自己的恶魔。我现在理解的是,我必须以某种方式知道最低价格的对象组合,而不是迭代整个组合列表,我似乎无法找到它。
有人可以建议任何让 maxLength 更高(理想情况下更高)的更改,而不会影响性能。任何帮助深表感谢。如果我不清楚,请告诉我。
private static int leastPrice = int.MaxValue;
private IEnumerable<IEnumerable<OBJECT>> CombinationOfObjects(IEnumerable<OBJECT> objects, int length)
{
if (length == 1)
return objects.Select(t => new OBJECT[] { t });
return CombinationOfObjects(objects, length - 1).SelectMany(t => objects, (t1, t2) => t1.Concat(new OBJECT[] { t2 }));
}
//Gets the least priced Valid combination out of all possible
public IEnumerable<OBJECT> GetValidCombination(IEnumerable<OBJECT> list, int maxLength, int[] matArray)
{
IEnumerable<IEnumerable<OBJECT>> tempList = null;
List<IEnumerable<OBJECT>> validList = new List<IEnumerable<OBJECT>>();
for (int i = 1; i <= maxLength; i++)
{
tempList = CombinationOfObjects(list, i);
tempList = from alist in tempList
orderby alist.Sum(x => x.Price)
select alist;
foreach (var lst in tempList)
{
//This check will not be required if the least priced value is returned as soon as found
int price = lst.Sum(c => c.Price);
if (price < leastPrice)
{
if (CheckMaterialSum(lst, matArray))
{
validList.Add(lst);
leastPrice = price;
break;
//return lst;
//returning lst as soon as valid combo is found is fastest
//Con being it also returns the least priced least item containing combo
//i.e. even if a 4 item combo is cheaper than the 2 item combo satisfying the need,
//it'll never even check for the 4 item combo
}
}
}
}
//This whole thing would go too if lst was returned earlier
foreach (IEnumerable<OBJECT> combination in validList)
{
int priceTotal = combination.Sum(combo => combo.Price);
if (priceTotal == leastPrice)
{
return combination;
}
}
return new List<OBJECT>();
}
//Checks if the given combination satisfies the requirement
private bool CheckMaterialSum(IEnumerable<OBJECT> combination, int[] matArray)
{
int[] sumMatProp = new int[matArray.Count()];
for (int i = 0; i < matArray.Count(); i++)
{
sumMatProp[i] = combination.Sum(combo => combo.Numbers[i]);
}
bool isCombinationValid = matArray.Zip(sumMatProp, (requirement, c) => c >= requirement).All(comboValid => comboValid);
return isCombinationValid;
}
static void Main(string[] args)
{
List<OBJECT> testList = new List<OBJECT>();
OBJECT object1 = new OBJECT();
object1.Name = "object1";
object1.Price = 2000;
object1.Numbers = new int[] { 2, 3, 4 };
testList.Add(object1);
OBJECT object2 = new OBJECT();
object2.Name = "object2";
object2.Price = 1900;
object2.Numbers = new int[] { 3, 2, 4 };
testList.Add(object1);
OBJECT object3 = new OBJECT();
object3.Name = "object3";
object3.Price = 1600;
object3.Numbers = new int[] { 4, 3, 2 };
testList.Add(object1);
int requiredNumbers = new int[]{10,10,10};
int maxLength = 9;//This is the max length possible, OutOf Mememory exception after this
IEnumerable<OBJECT> resultCombination = GetValidCombination(testList, maxLength, requiredNumbers);
}
修改
要求:
我有许多具有多个属性的对象,即 Price , Name 和 Materials 。现在,我需要找到这些对象的组合,即组合中所有材料的总和满足用户输入的材料数量。此外,组合需要尽可能低的价格。 存在 maxLength 的约束,它设置了组合中可以包含的最大对象总数,即对于 maxLength = 8,组合可以包含1中的任意值到8个物体。
尝试了方法:
1
- 我找到了所有对象组合(有效+无效)
- 对它们进行迭代以找到价格最低的组合。迭代时这会耗尽内存。
- 我找到所有可能的组合(有效+无效)
- 应用有效性检查(即,如果它满足用户要求)
- 仅在列表列表中添加有效组合
- 对这个有效的列表列表进行迭代,找到最便宜的列表并返回。也是内存不足
3
- 我按照对象的递增顺序找到组合(即首先是所有具有1个对象的组合,然后是2然后等等......)
- 根据价格排序组合
- 应用有效性检查并返回第一个有效组合
- 这样做效果很好,但并不总是返回最便宜的组合。
如果我能以某种方式获得最佳解决方案而不迭代整个列表,那将解决它。但是,我尝试的所有事情要么必须迭代所有组合,要么根本不会产生最佳解决方案。
对于我似乎无法想到的其他一些方法的任何帮助都是最受欢迎的。