这是一个类的IEnumerable。
IEnumerable<Card> cardList = new List<Card> {
new Card { CardNumber = 1234, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1235, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1236, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1237, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1238, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1239, Amount = 15m, DisplayText = "" },
new Card { CardNumber = 1240, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1241, Amount = 10m, DisplayText = "" },
new Card { CardNumber = 1242, Amount = 25m, DisplayText = "" },
new Card { CardNumber = 1243, Amount = 25m, DisplayText = "" },
new Card { CardNumber = 1244, Amount = 25m, DisplayText = "" },
new Card { CardNumber = 1245, Amount = 25m, DisplayText = "" }
};
我想要完成的是按照金额和顺序卡号对列表进行分组,这些组中至少有4张卡片,或者它们没有分组。 这是我想要实现的一个例子。 结果将是另一个IEnumerable 并包含此
Card { CardNumber = null, Amount = 10m, DisplayText = "1234 - 1238" },
Card { CardNumber = null, Amount = 15m, DisplayText = "1239" },
Card { CardNumber = null, Amount = 10m, DisplayText = "1240" },
Card { CardNumber = null, Amount = 10m, DisplayText = "1241" },
Card { CardNumber = null, Amount = 25m, DisplayText = "1242 - 1245" }
希望在我想要做的事情中明确这一点。任何帮助将非常感激。
谢谢,
答案 0 :(得分:2)
使用纯LINQ运算符是不可能的。但是可以使用混合标准和自定义LINQ之类的扩展方法。
创建一个自定义方法,允许我们根据谓词接收上一个和当前元素来拆分序列:
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, Func<T, T, bool> splitOn)
{
using (var e = source.GetEnumerator())
{
for (bool more = e.MoveNext(); more; )
{
var last = e.Current;
var group = new List<T> { last };
while ((more = e.MoveNext()) && !splitOn(last, e.Current))
group.Add(last = e.Current);
yield return group;
}
}
}
}
现在,您可以使用以下查询来实现目标:
var result = cardList.OrderBy(c => c.CardNumber)
.Split((prev, next) => prev.Amount != next.Amount || prev.CardNumber + 1 != next.CardNumber)
.SelectMany(g => g.Count() >= 4 ?
new [] { new Card { Amount = g.First().Amount, DisplayText = g.First().CardNumber + " - " + g.Last().CardNumber } } :
g.Select(c => new Card { Amount = c.Amount, DisplayText = c.CardNumber.ToString() }));
OrderBy
后跟自定义Split
执行初始分组。剩下的棘手部分是如何根据Count
条件对元素进行分组/取消分组,这是通过条件SelectMany
方法在一种情况下生成单个项目(通过选择单个项目数组)或展平来实现的。在另一种情况下,使用内部Select
组。
答案 1 :(得分:0)
我不认为使用LINQ可以完成这样的事情。
但是如果没有LINQ就可以很容易地实现这一点,例如:(我假设cardList
按CardNumber
排序}
List<Card> result = new List<Card>();
Func<List<Card>,List<Card>> bufferToResult = (buf) =>
{
List<Card> res = new List<Card>();
if(buf.Count >= 4) {
string text = buf[0].CardNumber + " - " + buf[buf.Count-1].CardNumber;
Card newCard = new Card { Amount = buf[0].Amount, DisplayText = text };
res.Add(newCard);
} else {
foreach(Card c in buf) {
Card newCard = new Card { Amount = c.Amount, DisplayText = c.CardNumber.ToString() };
res.Add(newCard);
}
}
return res;
};
List<Card> buffer = new List<Card>();
for(int i=0; i<cardList.Count(); ) {
Card card = cardList.ElementAt(i);
if(buffer.Count == 0) {
buffer.Add(card);
i++;
} else if(card.Amount == buffer[0].Amount) {
buffer.Add(card);
i++;
} else {
result.AddRange(bufferToResult(buffer));
buffer.Clear();
}
}
if(buffer.Count > 0)
result.AddRange(bufferToResult(buffer));
答案 2 :(得分:0)
您可以通过将通过约束的项目分组到新列表中,然后根据组大小填充第二个项目来实现这一目标:
IList<Card> group = new List<Card>();
IList<Card> result = new List<Card>();
for (int i = 0, j = 0; i < cardList.Count - 1; i++)
{
group.Clear();
group.Add(cardList[i]);
for (j = i + 1; j < cardList.Count; j++, i++)
{
if (cardList[j].Amount == cardList[i].Amount && cardList[j].CardNumber - cardList[i].CardNumber == 1)
{
group.Add(cardList[j]);
}
else break;
}
if (4 > group.Count)
{
foreach (var item in group)
{
result.Add(new Card { Amount = item.Amount, DisplayText = item.CardNumber.ToString() });
}
}
else
{
result.Add(new Card { Amount = group[0].Amount, DisplayText = string.Format("{0} - {1}", group[0].CardNumber, group.Last().CardNumber) });
}
}
使用LINQPad的结果:
CardNumber Amount DisplayText
null 10 1234 - 1238
null 15 1239
null 10 1240
null 10 1241
null 25 1242 - 1245
我比过于复杂的Linq代码更喜欢这个。