C# 基于值选择多个集合的最佳匹配组合
我有一个.net核心web应用程序,供我们的员工使用,根据他们输入的余额将产品与客户匹配。有5种类型的产品。产品1必须作为主要产品包含在每个捆绑包中。其他4种产品将根据该价值与尽可能多的产品捆绑在一起。但产品1也有多个不同的价位。因此,假设客户能够负担产品1的最高价格点,但只有2个插件。我需要它降到产品1的下一个值并添加每个插件等。有人能给我的任何指导都会很有帮助。假设您有一个包含C# 基于值选择多个集合的最佳匹配组合,c#,entity-framework,linq,C#,Entity Framework,Linq,我有一个.net核心web应用程序,供我们的员工使用,根据他们输入的余额将产品与客户匹配。有5种类型的产品。产品1必须作为主要产品包含在每个捆绑包中。其他4种产品将根据该价值与尽可能多的产品捆绑在一起。但产品1也有多个不同的价位。因此,假设客户能够负担产品1的最高价格点,但只有2个插件。我需要它降到产品1的下一个值并添加每个插件等。有人能给我的任何指导都会很有帮助。假设您有一个包含类型和价格的产品表 您可以将产品配置为类型1的产品和其他产品: var Prod1 = Products.Where
类型和价格的产品表
您可以将产品
配置为类型
1的产品和其他产品:
var Prod1 = Products.Where(p => p.Type == 1);
var ProdNot1 = Products.Where(p => p.Type != 1);
使用一些扩展方法,您可以创建非1型产品的所有可能组合(如果您是从数据库提取,则必须在内存中执行此操作):
使用最低价格的1类产品:
var minPriceProd1 = Prod1.MinBy(p => p.Price);
您可以使用CustBal
并猜测您对附加产品的预算:
var CustBal = 375;
var nonProd1BalGuess = CustBal - minPriceProd1.Price;
var finalProd1 = Prod1.Where(p => p.Price <= minPriceProd1.Price + allProdBalGuess).OrderByDescending(p => p.Price).First();
var nonProd1Bal = CustBal - finalProd1.Price;
然后,您可以猜测哪个附加组件组合将起作用,最大化类型数,优先考虑较低的类型,并采用最低价格:
var nonProd1Guess = AddOnCombos.Where(aoc => aoc.Price <= nonProd1BalGuess)
.OrderByDescending(aoc => aoc.Products.Count())
.ThenBy(aoc => aoc.Types)
.ThenBy(aoc => aoc.Price)
.FirstOrDefault();
然后计算类型1的最终产品以及附加产品的剩余量:
var CustBal = 375;
var nonProd1BalGuess = CustBal - minPriceProd1.Price;
var finalProd1 = Prod1.Where(p => p.Price <= minPriceProd1.Price + allProdBalGuess).OrderByDescending(p => p.Price).First();
var nonProd1Bal = CustBal - finalProd1.Price;
“尽可能多”是什么意思?在一个捆绑包中可以有任意产品的倍数吗?一般来说,减去最小产品1,首先减去其他产品的最小值,使用剩余的余额提升产品1等级。因此产品1有许多不同的价格点,因此产品1将始终作为主要产品包含在每个捆绑包中。其他每种产品都只有一种。产品是否有优先权,或者优先权是否包括尽可能多的产品,最多4种?如果您尽可能多地包含,是否有更高定价的优先权,例如,是否更倾向于使用比类型3更昂贵的类型2,或者这是否重要?是的,因此产品2的权重将高于产品3,产品3的权重将高于产品4等。如果您拥有所有5种产品(或4或3),并且剩余余额,是获得更高的Prod1,还是更高的Prod2,还是什么?
var finalProd1 = Prod1.Where(p => p.Price <= minPriceProd1.Price + allProdBalGuess).OrderByDescending(p => p.Price).First();
var nonProd1Bal = CustBal - finalProd1.Price;
var nonProd1 = AddOnCombos.Where(aoc => aoc.Price <= nonProd1Bal)
.OrderByDescending(aoc => aoc.Products.Count())
.ThenBy(aoc => aoc.Types)
.ThenByDescending(aoc => aoc.Price)
.ThenByDescending(aoc => Enumerable.Range(2, 5).Select(t => aoc.Products.FirstOrDefault(p => p.Type == t)?.Price ?? 0), new SeqCompare<double>())
.FirstOrDefault();
public static class IEnumerableExt {
public static int SeqCompareTo<T>(this IEnumerable<T> s1, IEnumerable<T> s2) => SequenceCompare(s1, s2);
public static int SequenceCompare<T>(IEnumerable<T> source1, IEnumerable<T> source2) {
// You could add an overload with this as a parameter
IComparer<T> elementComparer = Comparer<T>.Default;
using (IEnumerator<T> iterator1 = source1.GetEnumerator())
using (IEnumerator<T> iterator2 = source2.GetEnumerator()) {
while (true) {
bool next1 = iterator1.MoveNext();
bool next2 = iterator2.MoveNext();
if (!next1 && !next2) // Both sequences finished
return 0;
if (!next1) // Only the first sequence has finished
return -1;
if (!next2) // Only the second sequence has finished
return 1;
// Both are still going, compare current elements
int comparison = elementComparer.Compare(iterator1.Current,
iterator2.Current);
// If elements are non-equal, we're done
if (comparison != 0)
return comparison;
}
}
}
}
public class SeqCompare<T> : IComparer<IEnumerable<T>> {
public int Compare(IEnumerable<T> x, IEnumerable<T> y) => x.SeqCompareTo(y);
}