[英]How to return neighbouring items of an item in a LINQ query
考虑以下集合
var players = new[]{
new {Id = 1, Name = "A", Score = 70},
new {Id = 2, Name = "B", Score = 50},
new {Id = 3, Name = "C", Score = 100},
new {Id = 4, Name = "D", Score = 90}
};
如果我想按分数排序返回上面列表中特定玩家(例如,ID = 1的玩家)的位置,我可以编写如下查询:
var result = players.OrderByDescending(p => p.Score)
.Select((p, i) => new {player = p, Position = i})
.Where(x => x.player.Id == 1)
.First();
int position = result.Position;
var player = result.player;
现在,我该如何进一步处理并退还除实际玩家以外的其他物品 ? 当我们按分数排序列表时,相邻的项目是上一个和下一个玩家以及它们各自的位置。
这是查询的预期结果
var expectedResult = new[]{
new {Id = 2, Name = "B", Score = 50}, //Previous player
new {Id = 1, Name = "A", Score = 70},
new {Id = 4, Name = "D", Score = 90} //Next Player
};
是否可以通过单个LINQ表达式来获得上述结果? 任何帮助,将不胜感激。
您可以使用.NET 4.0中定义的Zip运算符,也可以使用Rx扩展中定义的Scan运算符:
带拉链:
var result = players.OrderByDescending(p => p.Score)
.Select((p, i) => new {Player = p, Position = i})
.ToList(); //forces evaluation
result.Zip(result.Skip(1), (i,j) => new {First= i, Second=j})
.Zip(result.Skip(2), (i,j) => new {First = i.First, Second = i.Second, Third=j})
.First(o => o.Second.player.Id == 1);
但是,这不会给您第一个和最后一个玩家的邻居。 如果您也想要它们,则必须对您的收藏进行按摩(因为所有三个同等数量的物品必须具有相同的数量)
我会这样写:
public static IEnumerable<IList<T>> GetOverlappingChunks<T>(
this IEnumerable<T> sequence, int chunkSize)
{
List<T> chunk = new List<T>(chunkSize);
foreach (var elt in sequence)
{
chunk.Add(elt);
if (chunk.Count > chunkSize)
chunk.RemoveAt(0);
if (chunk.Count == chunkSize)
yield return chunk.ToArray();
}
}
// ...
var result = players.OrderByDescending(p => p.Score)
.GetOverlappingChunks(3)
.Where(x => x[1].Id == 1);
(太糟糕的C#没有内置的双端队列类型。)
如果需要处理列表中少于三个玩家的情况,则需要微调GetOverlappingChunks
和检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.