简体   繁体   English

在列表中相互比较项目

[英]Comparing items with each other in a list

I have a List<DiscountRule> and I need to iterate over these checking to see if any of the rules clash with each other. 我有一个List<DiscountRule> ,我需要遍历这些检查以查看是否有任何规则相互冲突。 There are some properties on the rule such as BrandID and CategoryID which indicate which brand and category the rule applies to along with Include/Exclude flags. 规则上有一些属性,例如BrandIDCategoryID ,它们指示该规则适用于哪个品牌和类别以及“ Include/Exclude标志。

A rule would clash if both category and brand match an existing rule if the following example condition occurs: 如果发生以下示例条件,则类别和品牌都与现有规则匹配时,规则将发生冲突:

Rule 1 规则1

Include brand Include category 包括品牌包括类别

Rule 2 规则二

Exclude brand Exclude category 排除品牌排除类别

Obviously a clash can occur if a rule is Include Exclude and Exclude Include and vice versa which I also check for. 显然,如果规则是“包含排除”和“排除包含”,反之亦然,我也会检查该规则,则可能会发生冲突。

I need a way of looping over these and flagging those that are clashing within the list. 我需要一种遍历这些并标记列表中冲突的方法。 Here's what I currently have: 这是我目前拥有的:

public bool CheckDiscountRuleClash(DiscountRule other)
{
    if (this.CategoryId == other.CategoryId && this.BrandId == other.BrandId)
    {
        if (this.BrandInclude && this.CategoryInclude
         && !other.BrandInclude && !other.CategoryInclude)
        {
            this.RuleClashes = true;
            return true;
        }
        else if (!this.BrandInclude && !this.CategoryInclude
            && other.BrandInclude && other.CategoryInclude)
        {
            this.RuleClashes = true;
            return true;
        }
        else if (this.BrandInclude && !this.CategoryInclude
            && !other.BrandInclude && other.CategoryInclude)
        {
            this.RuleClashes = true;
            return true;
        }
        else if (!this.BrandInclude && this.CategoryInclude
                && other.BrandInclude && !other.CategoryInclude)
        {
            this.RuleClashes = true;
            return true;
        }
        else
        {
            this.RuleClashes = false;
            return false;
        }
    }

    return false;
}

Which I'm calling like: 我这样称呼:

rules.Where(i1 => rules.Any(i2 => i1.CheckDiscountRuleClash(i2))).ToList();

But this obviously only gives me back those which satisify the Any() condition. 但这显然只能带给我那些满足Any()条件的条件。 Is there a way to do what I want? 有什么方法可以做我想要的吗?

To get back all of the pairs that match your condition simply project each sequence into it's matches: 要获取所有符合条件的对,只需将每个序列投影到其匹配项中:

var conflictingRules = rules.SelectMany(rule => 
    rules.Where(other => rule.CheckDiscountRuleClash(other))
    .Select(other=> new { rule, other }));

How about using a foreach loop instead to make sure you go through every item in the list 如何使用foreach循环来确保您遍历列表中的每个项目呢?

foreach (var rule in rules) // where rules is your List<DiscountRule>
            {
                var result = CheckDiscountRuleClash(rule);
                // do something with the result here (boolean)
                ...
            }

You can do it with Linq join in linear time: 您可以使用线性时间的Linq join来做到这一点:

var conflictingRules =
            from rule in rules
            join other in rules
            on new{rule.BrandId, rule.CategoryId, rule.BrandInclude, rule.CategoryInclude} equals new{other.BrandId, other.CategoryId, BrandInclude = !other.BrandInclude, CategoryInclude = !other.CategoryInclude}
            select new{rule, other};

The idea is to join the list with the the 'counterparts' - the ones known to conflict the other. 想法是将列表与“对应部分”(已知会相互冲突的部分)一起加入。 Same approach also allows you to use the algorithm with an SQL database if you want. 如果需要,同样的方法还允许您将算法与SQL数据库一起使用。

Note that this algorithm works in linear time, an outperforms the ones iterating all pairs (for example with SelectMany, which is O(N^2)) that the other answers demonstrate, by orders of magnitude, starting from the list of few doesens of brands an categories. 请注意,此算法在线性时间内有效,其性能优于迭代所有对的算法(例如,使用SelectMany,即O(N ^ 2)),其他答案以数量级从数个不等式列表开始显示品牌一类。

Also note that this code does not use the original CheckDiscountRuleClash code, so it it's smaller by 30 lines of code . 还要注意,此代码不使用原始的CheckDiscountRuleClash代码,因此它要小30行代码。 You can check out the live code with performance comparision here: https://dotnetfiddle.net/ZtRfcz 您可以在此处通过性能比较来检查实时代码: https : //dotnetfiddle.net/ZtRfcz

Note that if you increase the numbers a bit, the slow method would leed to execution timeout at 5 seconds on dotnetfiddle. 请注意,如果您稍微增加一些数字,则慢速方法将导致dotnetfiddle上5秒的执行超时。 Take computation complexity serious! 认真考虑计算复杂性!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM