检查列表成员是否以 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

但是我需要有关如何检查"连续"的帮助。

检查列表成员是否以 4 个为一组,连续进行

按 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));