检查列表成员是否连续4个为一组

时间:2012-03-12 11:29:09

标签: c# algorithm

我有一个有坐标的对象列表。对象是这样的:

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

但我需要帮助来检查'连续'。

6 个答案:

答案 0 :(得分:1)

按Y值拆分列表中的所有值。

然后为每个拆分列表:

  • 检查所有Y值是否相等。
  • 对于X值:遍历列表,检查与前一个的差异是否与之前和之前的差异(检查是否存在项目)。

假设点是有序的(如在您的示例中),至少对于X坐标。

答案 1 :(得分:1)

功能:

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}
};

答案 2 :(得分:1)

首先,检查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座位可以成为

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 :(得分:1)

我认为你必须做多次检查:

  • 使用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开始的行等。您只需要确保座位是有序的(这将通过{{1完成) }})。

答案 4 :(得分:0)

这个函数应检查一系列整数中有四个,它们都是不同的,并且min比最小值小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)));

答案 5 :(得分:0)

已编辑:这似乎也通过了添加的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));