我正在使用linq过滤我的数据,即,如果数据是数字类型,则必须使用比较器,否则我需要字符串匹配。
即使我的linq查询在循环内,我目前也只能使一个过滤器工作。
List<(string col, string opr, string value)> ps = new List<(string col, string opr, string value)>();
Func<ShoeModels, string, string, float, bool> comparer = (ShoeModels a, string column, string op, float value) =>
{
switch (op)
{
case "lt": return a[column] < value;
case "gt": return a[column] > value;
case "gte": return a[column] >= value;
case "lte": return a[column] <= value;
case "ne": return a[column] != value;
default:
break;
}
return true;
};
for(i=5;i<query.count;i++)
{
if (ps[i].value.All(char.IsDigit))
{
query.numValue = float.Parse(ps[i].value);
}
else
{
query.filterValue = ps[i].value;
}
query.filterColumn = ps[i].col;
query.opr = ps[i].opr;
query.opr = query.opr.ToLower();
IEnumerable<ShoeModels> res = null;
if (query.opr == "gt" || query.opr == "lt" || query.opr == "gte" || query.opr == "lte" || query.opr == "ne")
{
IEnumerable<ShoeModels> tuyo = from p in loopData.Where(a => comparer(a, query.filterColumn, query.opr, query.numValue))
select p;
res = tuyo.ToList();
}
else if (query.opr.ToLower() == "like")
{
IEnumerable<ShoeModels> tuyo = from p in loopData.Where(a => a[query.filterColumn].Contains(query.filterValue))
select p;
res = tuyo.ToList();
}
finalResult = res.ToList();
}
正如您在代码中看到的那样,我正在使用LHS方括号运算符来过滤我的数据。现在,如果在比较之前使用我的like运算符,则会出现异常“ float不包含Contains的定义”。 因此,我通过阅读有关延迟执行的内容,然后在每次执行后将ToList()添加到结果中来解决了该问题。因此,现在存在一个问题,每当我尝试过滤代码时,只有最后一个过滤器可以工作,但是所有过滤器都应该工作。
答案 0 :(得分:0)
由于在loopData
循环的每次迭代中将过滤器应用于for
,所以只有最后一个过滤器起作用:
from p in loopData.Where()...
因此,每次您过滤初始loopData
时,都不会过滤之前过滤的结果。
您需要将每次迭代的初步过滤结果保存在其他应在for
循环之外声明的变量中(在我的代码示例中,此变量为res
变量)并应用其他过滤器到每次迭代中的res
变量。
List<ShoeModels> res = loopData; // here I declare and assign res variable, it should be outside of the loop
for (int i = 5; i < query.count; i++)
{
if (ps[i].value.All(char.IsDigit))
{
query.numValue = float.Parse(ps[i].value);
}
else
{
query.filterValue = ps[i].value;
}
query.filterColumn = ps[i].col;
query.opr = ps[i].opr;
query.opr = query.opr.ToLower();
IEnumerable<ShoeModels> tuyo = null;
if (query.opr == "gt" || query.opr == "lt" || query.opr == "gte" || query.opr == "lte" || query.opr == "ne")
{
// apply filtering to the res variable
tuyo = res.Where(a => comparer(a, query.filterColumn, query.opr, query.numValue));
}
else if (query.opr.ToLower() == "like")
{
// apply filtering to the res variable
tuyo = res.Where(a => a[query.filterColumn].Contains(query.filterValue));
}
// update res variable, so on the next iteration we will operate on updated (filtered) list
res = tuyo.ToList();
}
使用float
来表示价格或金钱是一种不良做法。使用decimal
类型。
我在LinqPad5中创建了一个演示(如果您不了解LinqPad,请安装并使用它-这非常有用,尤其是对于编写LINQ查询):
void Main()
{
var ps = new List<(string col, string opr, string value)>();
ps.Add(("0", "gt", "6"));
ps.Add(("1", "like", "30.0"));
ps.Add(("2", "ne", "60"));
var loopData = new List<ShoeModels> {
new ShoeModels { Range = new[] { 5.0m, 10.0m, 15.0m }}, // leaves out on first filter ps[0]
new ShoeModels { Range = new[] { 10.0m, 20.0m, 30.0m }},// leaves out on second filter ps[1]
new ShoeModels { Range = new[] { 10.0m, 30.0m, 30.0m }},// this is the final result of all three filters
new ShoeModels { Range = new[] { 15.0m, 30.0m, 60.0m }},// leaves out on third filter ps[2]
};
loopData.Dump("initial data");
List<ShoeModels> res = loopData;
var query = new Query();
for (int i = 0; i < ps.Count; i++)
{
decimal number;
if (Decimal.TryParse(ps[i].value, out number))
{
query.numValue = number;
}
else
{
query.filterValue = ps[i].value;
}
query.filterColumn = ps[i].col;
query.opr = ps[i].opr.ToLower();
IEnumerable<ShoeModels> tuyo = null;
if (query.opr == "gt" || query.opr == "lt" || query.opr == "gte" || query.opr == "lte" || query.opr == "ne")
{
tuyo = res.Where(a => comparer(a, query.filterColumn, query.opr, query.numValue));
}
else if (query.opr.ToLower() == "like")
{
tuyo = res.Where(a => (a[query.filterColumn]).ToString(CultureInfo.InvariantCulture).Contains(query.filterValue));
}
res = tuyo.ToList();
res.Dump("after " + i + " iteration");
}
res.Dump("final result");
}
private Func<ShoeModels, string, string, decimal, bool> comparer = (ShoeModels a, string column, string op, decimal value) =>
{
switch (op)
{
case "lt": return a[column] < value;
case "gt": return a[column] > value;
case "gte": return a[column] >= value;
case "lte": return a[column] <= value;
case "ne": return a[column] != value;
default:
break;
}
return true;
};
class Query {
public decimal numValue { get; set;}
public string filterValue { get; set;}
public string filterColumn {get; set;}
public string opr {get; set;}
}
class ShoeModels {
public decimal[] Range = new decimal[3];
public decimal this[string index] {
get => Range[int.Parse(index)];
}
public override string ToString() =>
$"{Range[0].ToString(CultureInfo.InvariantCulture)} " +
$"{Range[1].ToString(CultureInfo.InvariantCulture)} " +
$"{Range[2].ToString(CultureInfo.InvariantCulture)}";
}