如何使用多个条件在LINQ中进行分组?

时间:2019-05-07 20:26:28

标签: c# sql linq

有没有办法在ObservableCollection中获得所有可能的组合?

我有一个这样的模型:

    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
    public string MyProperty3 { get; set; }
    public string MyProperty4 { get; set; }
    public string MyProperty5 { get; set; }
    public string MyProperty6 { get; set; }
    public string MyProperty7 { get; set; }
    public string MyProperty8 { get; set; }

我用来自电子表格的数据填充此模型,但是某些值具有零或空值(需要排除)。有没有办法以相同的模式获得所有可能的组合?

例如,所有属性中值均不为0的所有组合,以及只有一个属性具有value且其他属性为零的所有组合,等等。

到目前为止,我有这样的事情:

var group1 = _sourceStructure.Where(c => c.MyProperty != "0" && c.MyProperty2 != "0" && c.MyProperty3 != "0" && c.MyProperty4 != "0"
        && c.MyProperty5 != "0" && c.MyProperty6 != "0" && c.MyProperty7 != "0" && c.MyProperty8 != "0");

但是我需要使用30多个案例进行评估,有没有办法使用LINQ或其他解决方案来获得所有可能的组合?

我想使用集合中的值构建一个SQL查询,但是如果该值具有0或为空,则不会将该值添加到查询中。我希望获得具有相同模式的所有组合,以便能够将具有相同模式的所有项目放入SQL的IN中。

输出数据将如下所示:

string query = @"Select field1, field2, field3, fieldn FROM table WHERE "

query = query + "field1 = " + _sourceStructure.MyProperty1;

query = query + "fieldN =  " + _sourceStructure.MyPropertyN;

基本上,我不在乎哪个值。我只需要使用相同的模式将集合与所有可能的组合进行分组。

从Excel中的原始文件中采样数据:

       MyProperty1 MyPropert2 MyPropertN
Row1      0          1           3
Row2      2          0           6
Row3      0          5           9
Row4      9          9           4
Row5      4          3           6
Row6      0          0           0

例如,在这里,我期望Row1和Row3将在同一组中(值不相同,但“结构”相同),然后Row4和Row5将是另一组Row6另一个,而Row2另一个。

2 个答案:

答案 0 :(得分:1)

将您的表UNPIVOT更改为以下内容:

 Observable     Property      Value
     A             1            0
     A             2            1
     A             3            2
     B             1            0
     B             2            0
     B             3            1
     C             1            1
     C             2            2
     C             3            3

所有属性中所有值均不同于0的组合:

SELECT Observable
FROM Table
GROUP BY Observable
HAVING SUM(CASE WHEN VALUE = 0 THEN 1 ELSE 0 END) = 0

只有一个属性具有值而其他属性为零时的所有组合:

SELECT Observable
FROM Table
GROUP BY Observable
HAVING COUNT(CASE WHEN VALUE > 0 THEN 1 END) = 1

SQL DEMO

答案 1 :(得分:1)

您可以使用反射来获取名为MyProperty n的所有属性,其中n为1,然后使用List s中的PropertyInfo来计算以下项的位掩码:填充的属性,然后按该值分组。

首先我使用一些扩展方法:

public static class StringExt {
    public static string Past(this string s, string starter) {
        var starterPos = s.IndexOf(starter);
        return starterPos == -1 ? String.Empty : s.Substring(starterPos + starter.Length);
    }
}

public static class NumericExt {
    public static int ToInt<T>(this T obj) => Convert.ToInt32(obj);

    public static int IntPow(this int x, int pow) {
        int ans = 1;

        while (pow != 0) {
            if ((pow & 0x1) == 1)
                ans *= x;
            x *= x;
            pow >>= 1;
        }
        return ans;
    }
}

现在,您可以收集感兴趣的属性,进行排序,然后为每一行计算位掩码:

var myPropInfos = typeof(COC).GetProperties()
                             .Where(pi => pi.Name.StartsWith("MyProperty"))
                             .OrderBy(pi => pi.Name.Past("MyProperty").ToInt()) // just in case properties aren't ordered
                             .ToList();
var GroupedFilters = src.Select(r => new { r, ValuedMask = myPropInfos.Select((pi, p) => pi.GetValue(r).ToString() != "0" ? 2.IntPow(p) : 0).Sum() })
                        .GroupBy(rm => rm.ValuedMask, rm => rm.r);

如果第一个属性不是以整数结尾,则需要测试以按顺序处理它,或者(特别是如果这些属性不是全部以数字结尾),则可以省略{{ 1}}并使用OrderBy返回的任何顺序-顺序并不重要。对于每种有价值的属性组合,返回的答案都是GetProperties,其中IGrouping的位掩码显示了哪些属性被重视。

如果您拥有31个以上的属性,则应切换为使用Key并创建明显的long扩展方法(LongPow)。