【问题标题】:How to find successive numbers in a List<int> with duplicates?如何在 List<int> 中找到重复的连续数字?
【发布时间】:2025-12-03 19:40:01
【问题描述】:

我很无聊,所以我决定尝试制作一个我自己的 Yahtzee 游戏,规则与实际游戏完全相同,只是想测试一下我的编程技巧(目前还不够出色)。

下面发布的代码用于检查顺子(小号和大号)。 我相信你可以自己看,但万一你看不到,它的工作原理是这样的:

所有 5 个骰子的值都放在一个 List 中,然后使用 List&lt;T&gt;.Sort() 方法对其进行排序。

现在它们应该在列表中按升序排序(例如 1、2、3、4、5)。

为了确定它是否是一条大直线,我只需使用一个 int 值,如果检测到一条小直线,它的值会加 1,然后由于我的“大直线 = 小直线 * 2”而找到一条大直线逻辑,这可能有缺陷,但对我来说似乎很有意义:)。

这可行,但并非总是如此,正如您可能看到的那样,如果我在中间某处有重复值(例如 1、2、3、3、4、6),则此代码将不起作用。这一系列数字应该仍然给我一个小顺,但它不会。

现在至于我的实际问题:如何修改此代码,以便它始终检测大小直道?

List<int> valList = new List<int>();
foreach (Dice d in dList)
{
    valList.Add(d.Value);
}
valList.Sort();

txtSmall.Text = "0";
txtLarge.Text = "0";
int straight = 0;
if (valList[0] == valList[1] - 1 && valList[1] == valList[2] - 1 && valList[2] == valList[3] - 1)
    straight++;
if (valList[1] == valList[2] - 1 && valList[2] == valList[3] - 1 && valList[3] == valList[4] - 1)
    straight++;
switch (straight)
{
    case 1:
        if (txtSmall.IsEnabled)
            txtSmall.Text = "30";
        break;
    case 2:
        if (txtSmall.IsEnabled)
            txtSmall.Text = "30";
        if (txtLarge.IsEnabled)
            txtLarge.Text = "40";
        break;
}

PS:以防你想知道我的Dice 课程是怎么上的,这里是(尽管我不明白你为什么需要它):

class Dice
{
    private static CryptoRandom r = new CryptoRandom();
    public static int uBound = 1;
    public static int lBound = 7;
    public string Path { get; set; }
    private int value;
    public int Value
    {
        get { return value; }
    }
    private bool locked;
    public bool Locked
    {
        get { return locked; }
    }

    public Dice(int lowerBound = 1, int upperBound = 6)
    {
        uBound = upperBound + 1;
        lBound = lowerBound;
        this.Roll();
        this.locked = false;
    }

    public void Roll()
    {
        this.value = r.Next(lBound, uBound);
    }

    public void Lock()
    {
        this.locked = true;
    }

    public void Unlock()
    {
        this.locked = false;
    }
}

PPS:如果有更好的方法来检测这些东西,请随时分享,但也请尝试回答我的问题 :)。

【问题讨论】:

    标签: c# list sorting


    【解决方案1】:

    如果性能不是问题并且我正确理解了问题,我会尝试这样的事情:

    var count = dList.Count; //6
    var straights = dList.Select(dice => dice.Value)
        .Distinct() //5,3,1,6,4
        .OrderBy(dice => dice.Value) //1,3,4,5,6
        .Select(dice => dice.Value + (count--)) //7,8,8,8,8
        .GroupBy(n => n) //[7,{7}],[8,{8,8,8,8}]
        .OrderByDecending(group => group.Count());
    
    var longestStraight = straights.First().Count(); //4
    

    【讨论】:

    • 我不太清楚您所说的dice =&gt; dice.Value 是什么意思,需要详细说明吗?我问的原因是因为我刚刚尝试了这段代码,我得到的只是一个错误:Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer&lt;int&gt;' because it is not a delegate type
    • 哦,对不起.. 我虽然你的 valListList&lt;Dice&gt; 类型。没关系,只是摆脱dice =&gt; dice.Value
    • 刚刚尝试过,但也没有用 :P 我确实有一个 List,但我会尝试一下 ;)
    • 我没有测试代码,所以可能会有一些错误,但逻辑应该可以。
    • 设法使用此代码使其工作:Code 它似乎工作,但是我刚刚得到一个序列 {3,4,5,5,5} 并且出于某种原因它仍然认为这是一条小直道(连续 4 条)。我没有检查你的逻辑的有效性,因为你的代码使用了我以前没有使用过的东西,而且我认为我不知道如何比你更好地使用它们。 :)
    【解决方案2】:

    一个非常简单的方法是在排序之前调用Distinct,这会删除所有重复项:

    List<int> allDice = new List<int>() { 1, 2, 3, 3, 4, 6 };
    IEnumerable<int> uniqueDice = allDice.Distinct();
    IEnumerable<int> sortedDice = uniqueDice.Sort(x => x);
    
    //etc.
    

    否则,您的方法是合理的。没有什么比找到小顺子更好的方法了。

    【讨论】:

    • The uniqueDice.Sort(...) 似乎不起作用:'System.Collections.Generic.IEnumerable&lt;int&gt;' does not contain a definition for 'Sort' and no extension method 'Sort' accepting a first argument of type 'System.Collections.Generic.IEnumerable&lt;int&gt;' could be found (are you missing a using directive or an assembly reference?) 我是遗漏了什么还是忘记添加什么? :P 没关系,我只是在调用Distinct() 方法之前对List&lt;int&gt; 进行了排序,现在似乎工作正常:)
    • 我刚刚发现的小问题,用这种方法,我不能正确检查直道了。正如我上面的代码检查其中包含 5 个项目的列表,这意味着如果它突然检查一个包含 4 个项目的列表,它将停止工作。我似乎无法弄清楚我可以用来完成这项工作的循环>.>
    • @Yorrick 不要对索引进行硬编码,而是针对 sortedDiceCount 方法使用 for 循环
    • 我做到了,但是我找不到正确的方法来检查所有内容而不超出范围(例如:for (int i = 0; i&lt;list.Count();i++) { if (list[i] == list[i+1] - 1) { ... } } 最终会超出范围。
    • @Yorrick 这样做你必须非常小心边界(因为你正在索引 i+1)。有个循环可以做到这一点,你甚至可以作为一个单独的问题提出。
    【解决方案3】:

    这是另一种方法,只是为了好玩:

    /// <summary>
    /// Determines if the dice passed in contain a strait
    /// </summary>
    /// <param name="dice">The dice to test</param>
    /// <returns>0 if there are no straits, 1 if there is a small strait, 
    /// or 2 if it contains both a large and small strait</returns>
    private static int ContainsStrait(IEnumerable<int> dice)
    {
        var uniqueDice = dice.Distinct().ToList();
        if (uniqueDice.Count < 4) return 0;
    
        uniqueDice.Sort();
    
        int consecutiveNumbers = 1;
        int lastValue = -1;
    
        foreach (var uniqueDie in uniqueDice)
        {
            if (uniqueDie == lastValue + 1)
            {
                consecutiveNumbers++;
            }
            else
            {
                consecutiveNumbers = 1;
            }
    
            lastValue = uniqueDie;
        }
    
        return (consecutiveNumbers > 4) ? 2 : (consecutiveNumbers > 3) ? 1 : 0;
    }
    

    测试它:

    private static void Main()
    {
        var rolls = new List<List<int>>
        {
            {new List<int> {3, 3, 3, 3, 3, 3}},
            {new List<int> {1, 2, 3, 4, 3, 2}},
            {new List<int> {2, 2, 3, 4, 5, 2}},
            {new List<int> {3, 3, 3, 4, 5, 6}},
            {new List<int> {1, 2, 3, 4, 5, 2}},
            {new List<int> {2, 2, 3, 4, 5, 6}}
        };
    
        foreach (var roll in rolls)
        {
            int result = ContainsStrait(roll);
    
            Console.WriteLine("The roll: {0} does {1}contain a small strait {2} a large strait",
                string.Join(", ", roll),
                result > 0 ? "" : "not ",
                result == 2 ? "and" : result == 1 ? "but not" : "or");
        }
    }
    

    【讨论】:

      【解决方案4】:

      为什么不把骰子放在一个数组中?

        int Sum = 0;
        int[] i = new int[5];
      

      这里的问题是,如果我们有双精度数,我们必须将它们移到数组的末尾。

        Array.Sort(i);
          for( int j = 0; j < 4; j++ )
        {
          int temp = 0;
          if( i[j] == i[j+1] )
          {
            temp = i[j];
      
            for( int k = j; k < 4; k++ )
            {
              i[k] = i[k+1];
            }
      
            i[4] = temp;
          }
        }
      

      完成后,这只是一个评估问题

      if( ((i[0] == 1) && (i[1] == 2) && (i[2] == 3) && (i[3] == 4)) ||
        ((i[0] == 2) && (i[1] == 3) && (i[2] == 4) && (i[3] == 5)) ||
        ((i[0] == 3) && (i[1] == 4) && (i[2] == 5) && (i[3] == 6)) ||
        ((i[1] == 1) && (i[2] == 2) && (i[3] == 3) && (i[4] == 4)) ||
        ((i[1] == 2) && (i[2] == 3) && (i[3] == 4) && (i[4] == 5)) ||
        ((i[1] == 3) && (i[2] == 4) && (i[3] == 5) && (i[4] == 6)) )
      {
       Sum = 30;
      }
      

      对于大直道来说,它更容易:

      Array.Sort(i)
      if( (i[0]+1 == i[1]) && (i[0]+2 == i[2]) && (i[0]+3 == i[3]) && (i[0]+4 == i[4]) )
      {
      Sum = 40;
      }
      

      【讨论】:

        最近更新 更多