如何以随机顺序显示字典中的项,但相邻的两个项不相同

本文关键字:两个 随机 顺序 显示 字典 | 更新日期: 2023-09-27 18:05:24

首先,实际上有比标题中说明的更多的限制。请她录制。

假设我有一个dictionary<char,int>,其中key作为项,value表示输出中出现的次数。(有点像加权,但没有替代)例('a',2) ('b',3) ('c',1)

可能的输出是'babcab'

我正在考虑下面的方法来实现它。

  1. 建立一个包含(累计权重,char)作为条目的新列表。
  2. 从列表中随机选择一个项目,
  3. 重新计算累计权重,并将最近绘制的项目权重设置为0。
  4. 重复。
在某种程度上,

可能会出现这样的情况:生成了'bacab',但不能做进一步的操作(因为只剩下'b',但权重被设置为0,因为不允许立即重复)。在这种情况下,我丢弃所有的结果并从头开始。

还有其他好的方法吗?

同样,如果我跳过"将相应的权重设置为0"的过程,而是拒绝任何不可行的解决方案呢?我已经得到了"bab"。在下一个循环选择中,我得到了"b",然后我重新绘制过程,直到我得到了不是"b"的东西,然后继续。这个效果更好吗?

如何以随机顺序显示字典中的项,但相邻的两个项不相同

这个递归算法怎么样?

  1. 创建一个所有字符的列表(候选列表),根据它们的权重重复它们。
  2. 创建一个空字符列表(您的解决方案列表)
  3. 从候选列表中随机选择一个条目
  4. 如果选中的项目(字符)与解决方案列表中的最后一个相同,则开始扫描候选列表中的另一个字符(如果需要,将其括起来)。
  5. 如果在步骤4中找不到这样的字符并且候选列表不为空,则返回
  6. 将选中的字符追加到解决方案列表中。
  7. 如果候选列表为空,打印出解决方案并'backtrack',否则转到步骤3。

我不太确定"回溯"步骤,但你应该有一个大致的想法。

试试这个,它应该生成一个(伪)随机排序的元素在您的枚举。我建议将你的字典整理成一个列表:

AKA的字典{b, 2}, {a, 3}变成{b} {b} {a} {a}

    public static IEnumerable<T> RandomPermutation<T>(this IEnumerable<T> enumerable)
    {
        if (enumerable.Count() < 1)
            throw new InvalidOperationException("Must have some elements yo");
        Random random = new Random(DateTime.Now.Millisecond);
        while (enumerable.Any())
        {
            int currentCount = enumerable.Count();
            int randomIndex = random.Next(0, currentCount);
            yield return enumerable.ElementAt(randomIndex);
            if (randomIndex == 0)
                enumerable = enumerable.Skip(1);
            else if (randomIndex + 1 == currentCount)
                enumerable = enumerable.Take(currentCount - 1);
            else
            {
                T removeditem = enumerable.ElementAt(randomIndex);
                enumerable = enumerable.Where(item => !item.Equals(removeditem));
            }
        }
    }

如果您需要额外的排列,只需再次调用它以获得另一个随机排序。虽然这不能得到所有的排列,但你应该能找到一些有用的东西。你也可以用它作为一个基线来得到一个解决方案。

这应该被分割成一些单独的方法,并且可以使用一些重构,但是我们的想法是以这样一种方式来实现它,它不依赖于随机移动东西,直到你得到一个有效的结果。这样你就无法预测要花多长时间

  • 将所有字符连接到一个字符串并随机化该字符串

  • 循环遍历随机字符串并查找违反

  • 规则的任何字符
  • 从字符串
  • 中删除该字符
  • 随机选择一个数字。使用这个数字作为"将被删除的字符放在第n个有效位置")
  • 循环剩余的字符串,找到第n个有效的位置来放回字符。
  • 如果没有有效的左位置,删除字符
  • 从步骤2重复,直到没有违规

    使用系统;使用System.Collections.Generic;

    RandomString

    名称空间{类项目{

        static void Main(string[] args)
        {
            Random rnd = new Random(DateTime.Now.Millisecond);
            Dictionary<char, int> chars = new Dictionary<char, int> { { 'a', 2 }, { 'b', 3 }, { 'c', 1 } };
            // Convert to a string with all chars
            string basestring = "";
            foreach (var pair in chars)
            {
                basestring += new String(pair.Key, pair.Value);
            }
            // Randomize the string
            string randomstring = "";
            while (basestring.Length > 0)
            {
                int randomIndex = rnd.Next(basestring.Length);
                randomstring += basestring.Substring(randomIndex, 1);
                basestring = basestring.Remove(randomIndex, 1);
            }
            // Now fix 'violations of the rule
            // this can be optimized by not starting over each time but this is easier to read
            bool done;
            do
            {
                Console.WriteLine("Current string: " + randomstring);
                done = true;
                char lastchar = randomstring[0];
                for (int i = 1; i < randomstring.Length; i++) 
                {                    
                    if (randomstring[i] == lastchar) 
                    {
                        // uhoh violation of the rule. We pick a random position to move it to
                        // this means it gets placed at the nth location where it doesn't violate the rule
                        Console.WriteLine("Violation at position {0} ({1})", i, randomstring[i]);
                        done = false;
                        char tomove = randomstring[i];
                        randomstring = randomstring.Remove(i, 1);
                        int putinposition = rnd.Next(randomstring.Length);
                        Console.WriteLine("Moving to {0}th valid position", putinposition);
                        bool anyplacefound;
                        do
                        {
                            anyplacefound = false;
                            for (int replace = 0; replace < randomstring.Length; replace++)
                            {
                                if (replace == 0 || randomstring[replace - 1] != tomove)
                                {
                                    // then no problem on the left side
                                    if (randomstring[replace] != tomove)
                                    {
                                        // no problem right either. We can put it here
                                        anyplacefound = true;
                                        if (putinposition == 0)
                                        {
                                            randomstring = randomstring.Insert(replace, tomove.ToString());
                                            break;
                                        }
                                        putinposition--;
                                    }
                                }
                            }
                        } while (putinposition > 0 && anyplacefound);
                        break;
                    }
                    lastchar = randomstring[i];
                }
            } while (!done);
            Console.WriteLine("Final string: " + randomstring);
            Console.ReadKey();
        }
    }
    

    }