C# 来自多个from语句的LINQ查询投影
我正在创建一个非常大的对象列表,这些对象都是多个集合中最小值、最大值和增量的可能组合 但是,我的问题是,如果不重新编写LINQ查询,就无法轻松排除一个或多个项集合。查询中“from”语句的顺序是根据传入的“loops”列表中的顺序推断出来的。在本例中,查询和最终投影到“步骤模型”列表中需要处理三个项目集。尽管“from”语句是LINQ语句,但它看起来仍然像是重复代码,可以将自身用于For循环。我不知道该怎么做,因为投影是在这个单一查询中组合的。 注意:我可能会添加更多集合,进一步加剧问题C# 来自多个from语句的LINQ查询投影,c#,linq,projection,C#,Linq,Projection,我正在创建一个非常大的对象列表,这些对象都是多个集合中最小值、最大值和增量的可能组合 但是,我的问题是,如果不重新编写LINQ查询,就无法轻松排除一个或多个项集合。查询中“from”语句的顺序是根据传入的“loops”列表中的顺序推断出来的。在本例中,查询和最终投影到“步骤模型”列表中需要处理三个项目集。尽管“from”语句是LINQ语句,但它看起来仍然像是重复代码,可以将自身用于For循环。我不知道该怎么做,因为投影是在这个单一查询中组合的。 注意:我可能会添加更多集合,进一步加剧问题 pub
public static IEnumerable<StepModel> CreateSteps(List<MinToMax> loops)
{
var steps =
from item1 in Enumerable
.Repeat(loops[0].Minimum, (loops[0].Maximum - loops[0].Minimum) / loops[0].Increment + 1)
.Select((tr, ti) => tr + loops[0].Increment * ti)
from item2 in Enumerable
.Repeat(loops[1].Minimum, (loops[1].Maximum - loops[1].Minimum) / loops[1].Increment + 1)
.Select((tr, ti) => tr + loops[1].Increment * ti)
from item3 in Enumerable
.Repeat(loops[2].Minimum, (loops[2].Maximum - loops[2].Minimum) / loops[2].Increment + 1)
.Select((tr, ti) => tr + loops[2].Increment * ti)
select new StepModel
{
ItemValues1 = new Step { Value = item1, IsActive = true },
ItemValues2 = new Step { Value = item2, IsActive = true },
ItemValues3 = new Step { Value = item3, IsActive = true },
};
return steps;
}
public class MinToMax
{
public int Minimum { get; set; }
public int Maximum { get; set; }
public int Increment { get; set; }
public bool IsActive { get; set; } = true;
}
public class Step
{
public int Value { get; set; }
public bool IsActive { get; set; } = true;
}
public class StepModel
{
public Step ItemValues1 { get; set; }
public Step ItemValues2 { get; set; }
public Step ItemValues3 { get; set; }
}
public class ItemSteps
{
public MinToMax ItemStep1 { get; } = new MinToMax();
public MinToMax ItemStep2 { get; } = new MinToMax();
public MinToMax ItemStep3 { get; } = new MinToMax();
}
public static List<MinToMax> GetValuesIntoSteps()
{
var list = new List<MinToMax>();
var itemValues = new ItemSteps();
itemValues.ItemStep1.Minimum = 10;
itemValues.ItemStep1.Maximum = 100;
itemValues.ItemStep1.Increment = 10;
if (itemValues.ItemStep1.IsActive)
{
list.Add(itemValues.ItemStep1);
}
itemValues.ItemStep2.Minimum = 3;
itemValues.ItemStep2.Maximum = 30;
itemValues.ItemStep2.Increment = 3;
if (itemValues.ItemStep2.IsActive)
{
list.Add(itemValues.ItemStep2);
}
itemValues.ItemStep3.Minimum = 15;
itemValues.ItemStep3.Maximum = 75;
itemValues.ItemStep3.Increment = 5;
if (itemValues.ItemStep3.IsActive)
{
list.Add(itemValues.ItemStep3);
}
return list;
}
公共静态IEnumerable CreateSteps(列表循环)
{
变量步骤=
来自可枚举项中的项1
。重复(循环[0]。最小值,(循环[0]。最大值-循环[0]。最小值)/循环[0]。增量+1)
.选择((tr,ti)=>tr+循环[0]。增量*ti)
来自可枚举项中的项2
。重复(循环[1]。最小值,(循环[1]。最大值-循环[1]。最小值)/循环[1]。增量+1)
.选择((tr,ti)=>tr+循环[1]。增量*ti)
来自可枚举项中的第3项
.重复(循环[2]。最小值,(循环[2]。最大值-循环[2]。最小值)/循环[2]。增量+1)
.选择((tr,ti)=>tr+循环[2]。增量*ti)
选择新的StepModel
{
ItemValues1=新步骤{Value=item1,IsActive=true},
ItemValues2=新步骤{Value=item2,IsActive=true},
ItemValues3=新步骤{Value=item3,IsActive=true},
};
返回步骤;
}
公共级MinToMax
{
公共整数最小值{get;set;}
公共整数最大值{get;set;}
公共整数增量{get;set;}
public bool IsActive{get;set;}=true;
}
公共类步骤
{
公共int值{get;set;}
public bool IsActive{get;set;}=true;
}
公共类模型
{
公共步骤ItemValues1{get;set;}
公共步骤ItemValues2{get;set;}
公共步骤ItemValues3{get;set;}
}
公共类ItemSteps
{
public MinToMax ItemStep1{get;}=new MinToMax();
public MinToMax ItemStep2{get;}=new MinToMax();
public MinToMax ItemStep3{get;}=new MinToMax();
}
公共静态列表GetValuesIntoSteps()
{
var list=新列表();
var itemValues=新的ItemSteps();
itemValues.ItemStep1.Minimum=10;
itemValues.ItemStep1.Maximum=100;
itemValues.ItemStep1.Increment=10;
if(itemValues.ItemStep1.IsActive)
{
添加(itemValues.ItemStep1);
}
itemValues.ItemStep2.Minimum=3;
itemValues.ItemStep2.Maximum=30;
itemValues.ItemStep2.Increment=3;
if(itemValues.ItemStep2.IsActive)
{
添加(itemValues.ItemStep2);
}
itemValues.ItemStep3.Minimum=15;
itemValues.ItemStep3.Maximum=75;
itemValues.ItemStep3.Increment=5;
if(itemValues.ItemStep3.IsActive)
{
添加(itemValues.ItemStep3);
}
退货清单;
}
您在这里尝试的操作可以在较高的层次上描述为任意数量序列的交叉连接
当您在LINQ中执行多个类似的from
子句时,这就是交叉连接。除了第一个之外,所有的功能都是调用SelectMany
。为了支持任意数量的输入,您需要对它们进行循环。不过,一个简单的foreach
循环不会很有效,因为第一个序列需要以稍微不同的方式处理
如何不同?两件事。首先,没有可调用的SelectMany
。如果你在一个空列表中调用它,你会得到另一个空列表。因此,循环中的第一个元素建立了基本列表。我在下面提供的实现确实是以空序列开始的,但是只有在循环中没有找到元素的情况下才有空序列。当找到第一个元素时,它将被替换。第二,至少在这个实现中,您需要从第一个元素发出一个新列表,而后续连接需要发出下一个元素并构造一个新列表
要记住的另一件事是,您需要一个可以处理任意数量元素的结果类型。为此,我选择了IEnumerable
——我选择List
作为元素类型,因为每个列表的每个索引都将与循环
参数的索引相关联,因此您可以直接对它们进行索引。例如,每个结果的元素[5]
将来自循环[5]
为了实现这一点,我直接使用IEnumerator
编写了相当于foreach
的循环。对于循环
中的第一个元素,它为每个要返回的结果构造一个步骤
对象列表
对于循环
中的每个后续项,它使用SelectMany
进行交叉联接,并将它们聚合到包含左侧元素和右侧元素的新列表中
枚举数公开当前属性。这使迭代不必绑定到给定的索引。您会注意到current
变量在loops[n]
以前使用的地方被使用
值得注意的是,对ToList
的调用是强制求值所必需的,因为current
变量与foreach
循环中的范围变量的捕获方式不同
这看起来是这样的:
公共静态IEnumerable CreateSteps(IEnumerable循环)
{
IEnumerable序列=Enumerable.Empty();
使用(IEnumerator enumerator=loops.GetEnumerator())
{
if(枚举数.MoveNext())
{
MinToMax current=枚举数.current;
序列=E