我收到了IEnumerable<TransactionLineDto>
。 TransactionLineDto
可以代表适用于Article
的{{1}}或Discount
。
订单很重要:Article
仅适用于前面的文章,直到找到另一个折扣。
根本没有折扣(只有Discount
代表TransactionLineDto
)。
一个Article
可以有很多折扣。
文章上的折扣不能超过1个。
示例:
IEnumerable<TransactionLineDto>
表示有3篇文章没有任何折扣。Article1 -> Article2 -> Article3
表示Article1 -> Article2 -> Discount1
适用于Discount1
和Article1
Article2
表示Article1 -> Article2 -> Discount1 -> Article3 -> Discount2 -> Article4
适用于Discount1
和Article1
,Article2
Discount2
,Article3
没有折扣{} LI>
醇>
现在我需要“分区”这些序列,以便能够知道哪个折扣适用于哪篇文章(必须放弃没有折扣的文章)。
第三个示例的预期输出应该是这样的:Article4
如何实现可以对此行为进行建模的数据结构/类?
我想到了类似的东西(注意我无法实现的(Discount1 -> Article1, Article2), (Discount2 -> Article3)
):
???
这是一个好方法还是过度杀伤? (我的意思是,只有使用预先存在的LINQ方法才能做到这一点吗?)
答案 0 :(得分:1)
使用基于APL扫描操作符的(我最喜欢的)自定义扩展方法(它就像Aggregate
只返回中间结果),您可以扫描反转的IEnumerable
并收集折扣,然后按折扣分组。
自定义扫描扩展方法:
public static IEnumerable<TResult> Scan<T, TResult>(this IEnumerable<T> src, TResult seed, Func<TResult, T, TResult> combine) {
foreach (var s in src) {
seed = combine(seed, s);
yield return seed;
}
}
然后您可以Scan
沿IEnumerable
收集每篇文章的折扣,然后按折扣分组:
var discountPartitions = src.Reverse()
.Scan((discount: (TransactionLineDto)null, article: (TransactionLineDto)null),
(daTuple, dto) => dto.IsDiscount ? (dto, (TransactionLineDto)null)
: (daTuple.discount != null ? (daTuple.discount, dto) : daTuple)
)
.Where(daTuple => daTuple.discount != null && daTuple.article != null)
.GroupBy(daTuple => daTuple.discount, daTuple => daTuple.article);
答案 1 :(得分:1)
public static IEnumerable<List<T>> ToClusters(
this IEnumerable<T> source, Func<T, bool> endOfClusterCriteria)
{
var result = List<T>();
foreach(T item in source)
{
result.Add(item);
if (endOfClusterCriteria(item))
{
yield return result;
result = new List<T>();
}
}
}
后:
var lookup = transactionLines
.ToClusters(line => line.IsDiscount())
.Where(cluster => 2 <= cluster.Count) //discard the discounts with no articles
.SelectMany(
cluster => cluster.Take(cluster.Count - 1),
(cluster, article) => new { Discount = cluster.Last(), Article = article })
.ToLookup(
pair => pair.Discount,
pair => pair.Article
).ToList();
我发现.SelectMany调用难以阅读,所以这与查询理解相同:
var lookup = (
from cluster in transactionLines.ToClusters(line => line.IsDiscount)
where 2 <= cluster.Count
from article in cluster.Take(cluster.Count - 1)
select new { Discount = cluster.Last(), Article = article }
).ToLookup(pair => pair.Discount, pair => pair.Article);