Stackoverflow
使用C# LINQ,如何选择集合中多个子类别的最后两个实例?
在下面的代码中,phaseRepository是一个阶段列表。

每个阶段都有一些属性,包括方向和动量(其中Momentum.Undefined应该被认为与Momentum.Time相同)。您将如何为四个子类别选择最后两个阶段实例:
答案类似于(不需要PhaseNumber命令):

为了提供帮助,下面的代码是一个LINQPad C#程序,它编译但缺少正确的答案:
void Main()
{
var phaseRepository = new PhaseRepository();
phaseRepository.Collection = GetCollection();
// answer in its current state is incorrect...
var answer = phaseRepository.Collection.Select(p => p);
answer.Dump();
}
private List<Phase> GetCollection()
{
return new List<Phase>
{
new Phase ()
{
PhaseNumber = 1,
Direction = Dir.Up,
Momentum = Mom.Price,
},
new Phase ()
{
PhaseNumber = 2,
Direction = Dir.Down,
Momentum = Mom.Time,
},
new Phase ()
{
PhaseNumber = 3,
Direction = Dir.Up,
Momentum = Mom.Price,
},
new Phase ()
{
PhaseNumber = 4,
Direction = Dir.Down,
Momentum = Mom.Time,
},
new Phase ()
{
PhaseNumber = 5,
Direction = Dir.Up,
Momentum = Mom.Time,
},
new Phase ()
{
PhaseNumber = 6,
Direction = Dir.Down,
Momentum = Mom.Undefined,
},
new Phase ()
{
PhaseNumber = 7,
Direction = Dir.Up,
Momentum = Mom.Price,
},
new Phase ()
{
PhaseNumber = 8,
Direction = Dir.Down,
Momentum = Mom.Price,
},
new Phase ()
{
PhaseNumber = 9,
Direction = Dir.Up,
Momentum = Mom.Price,
},
new Phase ()
{
PhaseNumber = 10,
Direction = Dir.Down,
Momentum = Mom.Time,
},
new Phase ()
{
PhaseNumber = 11,
Direction = Dir.Up,
Momentum = Mom.Time,
},
new Phase ()
{
PhaseNumber = 12,
Direction = Dir.Down,
Momentum = Mom.Undefined,
}
};
}
public class PhaseRepository
{
public List<Phase> Collection = new List<Phase>();
}
public class Phase
{
public int PhaseNumber { get; set; }
public Dir Direction { get; set; }
public Mom Momentum { get; set; }
}
public enum Dir
{
Up,
Down,
Undefined
}
public enum Mom
{
Price,
Time,
Undefined
}发布于 2015-11-18 10:36:32
将GroupBy和SelectMany结合起来很容易做到:
var answer = phaseRepository.Collection
.OrderBy(p => p.PhaseNumber); // prepare to enforce "last two" requirement
.GroupBy(p =>
new {
p.Direction,
Momentum = p.Momentum == Mom.Undefined ? Mom.Time : p.Momentum
})
.SelectMany(g => g.Skip(g.Count() - 2)) // skip all but 2 from each group
.OrderBy(p => p.PhaseNumber); // optional, to make verification easier这里最重要的一点是,GroupBy是有保证,可以在每个组中保留源序列中元素的相对顺序:
IGrouping对象是根据源元素的顺序生成的,这些元素产生每个IGrouping的第一个键。分组中的元素是按照生成它们的元素出现在源中的顺序产生的。
因此,初始的逐阶段排序最初就足以满足“每个组中的最后两个”的要求。
发布于 2015-11-18 10:24:06
对于Direction.Up & Momentum.Price:
phaseRepository.Where(phase =>
{
phase.Direction == Direction.Up &&
phase.Momentum == Momentum.Price
}).Reverse().Take(2);您可以将此应用于所有其他需求。如果您希望未定义的时间与时间相同,只需检查phase.Momentum == Momentum.Time || phase.Momentum == Momentum.Undefined
如果您想要最后一个2 PhaseNumbers,那么在这个数字上使用OrderByDescending(x => x.PhaseNumber),然后从它中使用.Take(2)。
如果Where()返回的元素少于2个,则Take(2)仍将返回一个空列表(如果Where()返回1项,则返回1个元素)。
发布于 2015-11-18 10:26:51
像这样的东西应该能起作用
phaseRepository.Collection
.GroupBy(x => Tuple.Create(x.Direction, x.Momentum))
.Where(x => x.Key == //filter on your desired sub catagories
.Select(x => x.OrderBy(y=>y.PhaseNumber).Take(2).ToList()) //get just the last 2 items
.SelectMany(x => x)
.OrderBy(y=>PhaseNumber) //return in complete orderhttps://stackoverflow.com/questions/33777260
复制相似问题