检查列表成员是否以 4 个为一组,连续进行
本文关键字:一组 连续 是否 成员 列表 检查 | 更新日期: 2023-09-27 18:27:33
我有一个有坐标的对象列表。对象是这样的:
private class Seats
{
public string Code { get; set; }
public long PosX { get; set; }
public long PosY { get; set; }
}
对于列表中的所有座位,我需要知道它们在 4 组,水平行中。例如,下面的列表很好:
List<Seats> good = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0}
};
下面的列表也可以(两行(:
List<Seats> good = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0},
new Seats {Code = "B1", PosX = 0, PosY = 1},
new Seats {Code = "B2", PosX = 1, PosY = 1},
new Seats {Code = "B3", PosX = 2, PosY = 1},
new Seats {Code = "B4", PosX = 3, PosY = 1}
};
下面的列表也可以(同一行,两组,差距在 (4,0((:
List<Seats> good = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0},
new Seats {Code = "A6", PosX = 5, PosY = 0},
new Seats {Code = "A7", PosX = 6, PosY = 0},
new Seats {Code = "A8", PosX = 7, PosY = 0},
new Seats {Code = "A9", PosX = 8, PosY = 0}
};
但是下面的列表是不行的,因为在 (3,0( 处有一个差距:
List<Seats> bad1 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A5", PosX = 4, PosY = 0}
};
下面的列表也不行,因为有五个:
List<Seats> bad2 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0},
new Seats {Code = "A5", PosX = 4, PosY = 0}
};
下面的列表也不行,因为四个座位需要放在水平行中:
List<Seats> bad3 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "B1", PosX = 0, PosY = 1},
new Seats {Code = "B2", PosX = 1, PosY = 1}
};
用于检查 4 的乘法(可以是 8、12 等(我只能做:
list.Count % 4 == 0
但是我需要有关如何检查"连续"的帮助。
按 Y 值拆分列表中的所有值。
然后对于每个拆分列表:
- 检查所有 Y 值是否相等。
- 对于 X 值:遍历列表,并检查与前一个和之前的差值是否等于前一个和之前(检查项目是否存在(。
假设点是有序的(如您的示例所示(,至少对于 X 坐标而言。
函数:
static bool IsGood(List<Seats> seats)
{
int size = 4;
return seats.GroupBy(s => s.PosY)
.Select(yGroup => new {
yCount = yGroup.Count(),
xCount = yGroup.GroupBy(x => x.PosX).Count(),
xDistance = yGroup.Max(x => x.PosX) - yGroup.Min(x => x.PosX)
})
.All(g => g.yCount == size && g.xCount == size && g.xDistance == size - 1);
}
测试:
Console.WriteLine("{0} is {1}", "good1", IsGood(good1) ? "good" : "bad");
Console.WriteLine("{0} is {1}", "good2", IsGood(good2) ? "good" : "bad");
Console.WriteLine("{0} is {1}", "bad1", IsGood(bad1) ? "good" : "bad");
Console.WriteLine("{0} is {1}", "bad2", IsGood(bad2) ? "good" : "bad");
Console.WriteLine("{0} is {1}", "bad3", IsGood(bad3) ? "good" : "bad");
Console.WriteLine("{0} is {1}", "bad4", IsGood(bad4) ? "good" : "bad");
输出:
good1 is good
good2 is good
bad1 is bad
bad2 is bad
bad3 is bad
bad4 is bad
测试数据:
List<Seats> good1 = new List<Seats>
{
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0}
};
List<Seats> good2 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0},
new Seats {Code = "B1", PosX = 0, PosY = 1},
new Seats {Code = "B2", PosX = 1, PosY = 1},
new Seats {Code = "B3", PosX = 2, PosY = 1},
new Seats {Code = "B4", PosX = 3, PosY = 1}
};
List<Seats> bad1 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A5", PosX = 4, PosY = 0}
};
List<Seats> bad2 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "A3", PosX = 2, PosY = 0},
new Seats {Code = "A4", PosX = 3, PosY = 0},
new Seats {Code = "A5", PosX = 4, PosY = 0}
};
List<Seats> bad3 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 1, PosY = 0},
new Seats {Code = "B1", PosX = 0, PosY = 1},
new Seats {Code = "B2", PosX = 1, PosY = 1}
};
List<Seats> bad4 = new List<Seats> {
new Seats {Code = "A1", PosX = 0, PosY = 0},
new Seats {Code = "A2", PosX = 0, PosY = 0},
new Seats {Code = "B1", PosX = 0, PosY = 0},
new Seats {Code = "B2", PosX = 0, PosY = 0}
};
我认为您必须进行多项检查:
- 使用
var result = seats.GroupBy(seat => seat.PosY)
和result.All(group => group.Count == 4)
检查每个 PosY 中是否有四个元素。 - 之后检查是否有间隙
var noGaps = groups.All(group => SeatGapFinder.Check(group.OrderBy(seat => seat.PosX)));
- 根据需要实施进一步检查... ;-(
这里是间隙查找器的代码:
public static class SeatGapFinder
{
public static bool Check(IEnumerable<Seats> seats)
{
using (var enumerator = seats.GetEnumerator())
{
if (!enumerator.MoveNext())
{
return false;
}
var lastValue = enumerator.Current.PosX;
while (enumerator.MoveNext())
{
lastValue++;
if (enumerator.Current.PosX != lastValue)
{
return false;
}
}
return true;
}
}
}
由于间隙查找器始终使用最后一个值,因此它还可以处理从 7 到 11 等的行。您只需要确保订购座位(这将通过group.OrderBy(seat => seat.PosX)
完成(。
首先,检查 PosY 是否都相同,然后检查最后一个 PosX 是否等于第一个 PosX + 元素数。
即,如果第一个 X 是 2,并且有 4 个元素,那么最后一个 X 必须是 5。
public bool IsGoodSeats(List<Seats> seats, int goodNumber)
{
if(seats.Count( seat => seat.PosY == seats[0].PosY) == goodNumber)
{
//var orderedSeats = seats.OrderBy(seat => seat.PosX);
//return orderedSeats.Last().PosX == (orderedSeats.First().PosX + goodNumber - 1);
// Actually Min and Max are better than ordering the list twice
return seats.select(s => s.PosX).Max() == (seats.select(s => s.PosX).Min() + goodNumber - 1);
}
return false;
}
更新我看到问题已经扩展,现在每组 4 个后允许有一个间隙。假设列表按 Y 排序,然后按 X 排序,样本是。
public bool IsAllGoodSeats(List<Seat> seats, int goodNumber)
{
if(seats.Count % goodNumber != 0)
return false;
for(int i = 0; i < seats.Count; i += goodNumber)
{
var subSeats = new List<Seat>();
for(int s = i; s < i + goodNumber; s++)
subSeats.Add(seats[s]);
if(!IsGoodSeats(subSeats, goodNumber))
return false;
}
return true;
}
另外,因为我们现在假设座位是按Y然后X排序的,IsGood Seats可以成为
public bool IsGoodSeats(List<Seats> seats, int goodNumber)
{
if(seats.Count( seat => seat.PosY == seats[0].PosY) == goodNumber)
{
return seats[goodNumber - 1].PosX == (seats[0].PosX + goodNumber - 1);
}
return false;
}
这个函数应该检查一系列整数中是否有四个,它们都是不同的,并且最小值是否比最大值小 3 - 因此连续有四个。它不需要四个人按顺序排列。
Func<IEnumerable<int>, bool> rowIsGood = xVals =>
xVals.Count() == 4 &&
xVals.Distinct().Count() == 4 &&
xVals.Min() + 3 == xVals.Max();
这应该按行对座位进行分组,并检查每排是否良好。
bool allRowsGood = seats.GroupBy(s => s.PosY).All(r => rowIsGood(r.Select(s => s.PosX)));
编辑:这似乎也通过了添加的good3
情况。
static bool CheckNGroups(IEnumerable<long> groupCont, int n = 4) {
var lst = groupCont.ToList();
lst.Sort();
for(int i = 0; i < lst.Count; i+=n) {
if (lst[i + (n - 1)] - lst[i] != n - 1) return false;
}
return true;
}
/* ... */
var bad = seatlist.GroupBy(s => s.PosY).Select((group) => group.Select(seat => seat.PosX).Distinct()).Any(xs => xs.Count() % 4 != 0 || !CheckNGroups(xs));