c# - 随机化列表,同时确保重复项不连续

标签 c# algorithm list sorting random

我正在寻找一种随机化列表顺序的有效机制,但需要注意的是,如果列表的长度允许,重复的项目之间必须至少有 9 个项目,否则它们之间的距离必须与长度一样远列表的允许。

首先,这仅适用于小型数据集,列表中的项目永远不会超过 150 个,可能只有 1 个。

所以基本前提是这样的:

  1. 列出可能包含一些重复的人名(通常任何给定名称的实例永远不会超过 2 个,但在特殊情况下可能有 3 个)
  2. 随机化列表(我已经使用 Fisher-Yates(或 Knuth 洗牌)让这部分工作)
  3. 如果列表包含重复项,请找出它们之间少于 9 项的项,并尽可能进行调整以使差距至少达到 9 项。

第 3 部分是棘手的部分,我没有关于系统应如何确保间距正确的任何业务规则的指南,只是在可能的情况下应该如此. 在最简单的层面上,检查违规然后适当移动列表元素的迭代循环似乎是可行的方法,但我可以想象几种情况,其中对一对进行调整然后导致另一对出现问题,依此类推。

我不是在找人为此编写代码,我只是想找到一些明智的想法,以一种好的、有效的方式来解决这个问题。

源列表将是 IList<string>C#以供引用。

最佳答案

尝试下面的代码。我使用 Linq 将字符串组合在一起以获取所有重复项。然后我创建一个随机的唯一字符串列表。然后将剩余的重复项添加到列表中,将字符串均匀分布。结果完全随机且分布均匀。

注意:我发现了一个小错误。更改下面的行

from : firstItem += spacing;​
to : firstItem += spacing + 1;​

在调试代码时,我发现 firstItem 偶尔会变为负数,因此我添加了代码以确保 firstItem 始终为正数。然后我开始思考为什么在 firstItem 大于数组大小的情况下我没有得到任何溢出。那是当我意识到我必须在间距上加 1 时。带有数组 A、B、C、D、E 的旧代码将给出 1、1、1、1、1、A、B、C、D、E。新代码将给出 1,A,1,B,1,C,1,D,1,E。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication20
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random();
            List<string> input = new List<string>();
            List<string> output = new List<string>();
            //create 150 random strings with duplicates
            for(int i = 0; i < 150; i++)
            {
                input.Add(rand.Next(0,25).ToString());
            }
            //create dictionary with two columns key, number of entries
            Dictionary<string, Value> dict = input.AsEnumerable()
                .GroupBy(x => x)
                .ToDictionary(x => x.Key, y => new Value { count = y.Count(), ranNumber = rand.Next() });

            dict = dict.OrderBy(x => x.Value.ranNumber).ToDictionary(x => x.Key, y => y.Value);
            //add 1 sorted numbers to output
            foreach(string key in dict.Keys)
            {
                output.Add(key);
            }
            //add rest of numbers
            foreach (string key in dict.Keys)
            {
                int numberOfItems = dict[key].count;
                if (dict[key].count > 1)
                {
                    int arraySize = output.Count;
                    int spacing = arraySize / numberOfItems;
                    int firstItem = 0;
                    //center around middle
                    if (numberOfItems % 2 == 0)
                    {
                        firstItem = (arraySize / 2) - (((numberOfItems / 2) * spacing) + (spacing / 2));
                    }
                    else
                    {
                        firstItem = (arraySize / 2) - (((numberOfItems - 1) / 2) * spacing);
                    }
                    if (firstItem < 0)
                    {
                        firstItem = 0;
                    }
                    //remove existing item
                    output.Remove(key);
                    //insert items
                    for (int i = 0; i < numberOfItems; i++)
                    {
                        output.Insert(firstItem,key);
                        firstItem += spacing;
                    }
                }
            }

            
        }
        public class Value
        {
            public int count { get; set; }
            public int ranNumber { get; set; }
        }

    }
}

关于c# - 随机化列表,同时确保重复项不连续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29797136/

相关文章:

c# - 从后面的代码多次将文本添加到文本框?

c# - 如何在第一次点击时激活组合框(Datagridview)

algorithm - 一个顶点的团

algorithm - 两个平方和 : Where's My Error?

python - 连接列表 : Python 的元素

python - python 嵌套列表中的求和值

c# - 如何为颜色选择器 (wpf) 创建颜色 Canvas

c++ - 如何找到除数以最大化余数?

c# - .NET 泛型 - 比较两个列表并过滤 : best practice

c# - Lambda 或 LINQ 按 Shift 对列表 <Employee> 进行排序,C#