在C#中使用LINQ过滤可变数量的参数

jmo0nnb3  于 2024-01-03  发布在  C#
关注(0)|答案(2)|浏览(249)

我有一个DataSet和一个DataTable,现在我想要一种通用的方法来检查不同的LINQ查询是否返回任何匹配。
例如,假设我有一个名为MyTable的表,其中包含以下数据。

  1. Col1 Col2 Col3 Col4
  2. A1 B1 C1 D1
  3. A2 B2 C2 D2
  4. A3 B3 C3 D3

字符串
我现在想要一个函数Conflicting,我可以用任意数量的参数来表示列和值。如果所有参数都匹配任何一行,Conflicting应该返回true。

  1. Conflicting(MyTable, (Col1,A1)) //returns True
  2. Conflicting(MyTable, (Col1,A1), (Col2,B1),(Col3,C1), (Col4,D1)) //returns True
  3. Conflicting(MyTable, (Col1,A1), (Col2,D1)) //returns False


这就是我现在的代码,问题是代码只用于检查是否存在一个列设置为特定值的行。

  1. public static bool Conflicting(string table, string colum, string value)
  2. {
  3. DataTable dt = state.Tables[table];
  4. var lines =
  5. from s in dt.AsEnumerable()
  6. where s.Field<string>(parameter) == value
  7. select new
  8. {
  9. ID = s.Field<Int32>(table + "ID")
  10. };
  11. var count = lines.Count();
  12. return count > 0;
  13. }

0sgqnhkj

0sgqnhkj1#

(You可以使用其他东西来保存参数,而不是Tuple,例如KeyValuePair
列可以是任何类型,而且字段的值可以为null。

  1. public static bool Conflicting(this DataTable dt, params Tuple<string, object>[] columnWithValue)
  2. {
  3. return dt.AsEnumerable().Any(row =>
  4. {
  5. for (int i = 0; i < columnWithValue.Length; i++)
  6. {
  7. // check for null values
  8. if (row.IsNull(columnWithValue[i].Item1))
  9. {
  10. if (columnWithValue[i].Item2 != null)
  11. return false;
  12. }
  13. else
  14. {
  15. if (!row[columnWithValue[i].Item1].Equals(columnWithValue[i].Item2))
  16. return false;
  17. }
  18. }
  19. return true;
  20. });
  21. }

字符串
使用代码:

  1. DataTable dt = new DataTable();
  2. dt.Columns.Add("ColA", typeof(string));
  3. dt.Columns.Add("ColB", typeof(string));
  4. dt.Columns.Add("ColC", typeof(string));
  5. dt.Columns.Add("ColD", typeof(string));
  6. dt.Rows.Add("A", null, "C", "D");
  7. for (int i = 1; i < 10; i++)
  8. dt.Rows.Add("A" + i, "B" + i, "C" + i, "D" + i);
  9. bool res = dt.Conflicting(
  10. Tuple.Create<string,object>("ColA", "A1"),
  11. Tuple.Create<string,object>("ColB", "B1")
  12. );
  13. Console.WriteLine(res); //true
  14. res = dt.Conflicting(
  15. Tuple.Create<string, object>("ColA", "A1"),
  16. Tuple.Create<string, object>("ColB", "B11")
  17. );
  18. Console.WriteLine(res);//false
  19. res = dt.Conflicting(
  20. Tuple.Create<string, object>("ColA", "A2"),
  21. Tuple.Create<string, object>("ColB", "B2"),
  22. Tuple.Create<string, object>("ColC", "C2"),
  23. Tuple.Create<string, object>("ColD", "D2")
  24. );
  25. Console.WriteLine(res);//true
  26. res = dt.Conflicting(
  27. Tuple.Create<string, object>("ColA", "A"),
  28. Tuple.Create<string, object>("ColB", null)
  29. );
  30. Console.WriteLine(res);//true


同样的结果也可以用一个Linq语句来实现:

  1. public static bool Conflicting(this DataTable dt, params Tuple<string, object>[] columnWithValue)
  2. {
  3. return dt.AsEnumerable().Any(row => columnWithValue.All(col => row.IsNull(col.Item1) ? col.Item2 == null : row[col.Item1].Equals(col.Item2)));
  4. }

展开查看全部
4ktjp1zp

4ktjp1zp2#

从你的例子中,我不清楚如果在任何一行中找到了 any 输入,或者如果必须在某一行中找到它们 all,你是否要返回true
前者更简单,所以这里有一个例子:

  1. static bool Conflicting(string table, params Tuple<string, string>[] columnValuePairs)
  2. {
  3. DataTable dt = state.Tables[table];
  4. return dt.AsEnumerable().Any(
  5. row => columnValuePairs.Any(p => row.Field<string>(p.Item1) == p.Item2));
  6. }

字符串
你可以这样调用上面的代码:

  1. Conflicting("MyTable",
  2. Tuple.Create("Col1", "A1"),
  3. Tuple.Create("Col2", "B1"),
  4. Tuple.Create("Col3", "C1"),
  5. Tuple.Create("Col4", "D1"));

编辑:

根据您更新的问题,您在其中指出您想要后一种行为,即给定列/值对中的 each 必须在 some 行中找到,以下应该起作用:

  1. static bool Conflicting(string table, params Tuple<string, string>[] columnValuePairs)
  2. {
  3. DataTable dt = state.Tables[table];
  4. var remainingPairs = new List<Tuple<string, string>>(columnValuePairs);
  5. foreach (var row in dt.AsEnumerable())
  6. {
  7. int i = 0;
  8. while (i < remainingPairs.Count)
  9. {
  10. Tuple<string, string> columnValuePair = remainingPairs[i];
  11. if (row.Field<string>(columnValuePair.Item1) == columnValuePair.Item2)
  12. {
  13. remainingPairs.RemoveAt(i);
  14. continue;
  15. }
  16. i++:
  17. }
  18. if (remainingPairs.Count == 0)
  19. {
  20. return true;
  21. }
  22. }
  23. return false;
  24. }


上面的方法检查每一行以查找该行的任何匹配列/值对,从列/值对列表中删除该列/值对以查找是否匹配。如果要查找的列/值对列表为空,则该方法返回true,从而找到了所有请求的列/值对。如果枚举了表中的所有行而没有清空列表,则某对不匹配任何行,方法返回false
请注意,上面的方法并不是实现这一点的唯一方法。实际上,如果您希望有大量的列/值对,那么为了提高性能,您可能需要一些不同的方法,例如使用哈希集或字典(两者都可以使用,但它们都有其特定的优点和缺点)。(最多几十个)列/值对,一个列表就足够了,而且它确实保持了实现的简单性。

展开查看全部

相关问题