C# 从列表中选择随机字符串<;字符串>;带有排除和非重复拾取

C# 从列表中选择随机字符串<;字符串>;带有排除和非重复拾取,c#,string,random,enumerable,C#,String,Random,Enumerable,我正在尝试编写一个程序,让用户: 加载一组字符串 在集合中循环,并从同一集合中拾取另一个字符串 避免再次拾取拾取的字符串 具有特定字符串无法拾取指定字符串 示例如下表所示: 下表是一个示例场景: 我怎么能用简单的方法做到这一点 我有下面的代码,但是生成一个有效的集合需要花费很长时间,因为如果没有什么可选择的,它会重新启动所有内容,而不会消除这种可能性 private List<Participant> _participants; AllOverAgain: var pick

我正在尝试编写一个程序,让用户:

  • 加载一组字符串
  • 在集合中循环,并从同一集合中拾取另一个字符串
  • 避免再次拾取拾取的字符串
  • 具有特定字符串无法拾取指定字符串
  • 示例如下表所示:

    下表是一个示例场景:

    我怎么能用简单的方法做到这一点

    我有下面的代码,但是生成一个有效的集合需要花费很长时间,因为如果没有什么可选择的,它会重新启动所有内容,而不会消除这种可能性

    private List<Participant> _participants;
    
    AllOverAgain:
    
    var pickedParticipants = new List<Participant>();
    var participantPicks = new List<ParticipantPick>();
    
    foreach(var participant in _participants)
    {
        var pickedParticipantNames = from rp in participantPicks select rp.PickedParticipant;
    
        var picks = (from p in _participants where p.Name != participant.Name & !Utilities.IsInList(p.Name, pickedParticipantNames) select p).ToList();
    
        var pick = picks[new Random().Next(0, picks.Count())];
    
        if(pick == null)
        {
            UpdateStatus($"No Available Picks left for {participant.Name}, Restarting...");
            goto AllOverAgain;
        }
    
        var exclusions = participant.Exclusions.Split(',').Select(p => p.Trim()).ToList();
    
        if(exclusions.Contains(pick.Name))
        {
            UpdateStatus($"No Available Picks left for {participant.Name}, Restarting...");
    
            goto AllOverAgain;
        }
    
        participantPicks.Add(new ParticipantPick(participant.Name, pick.Name, participant.Number));
    }
    
    return participantPicks; // Returns the final output result
    
    ParticipantPick
    类由以下属性组成:

    public string Name { get; set; }
    public string Number { get; set; }
    public string Exclusions { get; set; }
    
    public string Participant { get; set; }
    public string PickedParticipant { get; set; }
    public string Number { get; set; }
    

    解决此问题的一种方法是使用
    字典
    ,使用
    元组
    的复合键和数据类型的匹配值
    bool

    Dictionary<Tuple<string, string>, bool>
    
    …表明朱迪思选择詹姆斯是有效的

    因此,让我们为参与者的每个可能组合创建一个字典,并将它们的值设置为
    true
    ,以便它们在程序开始时有效

    这可以通过一个简单的方法来实现

    您可以通过以下方式使用循环将参与者从拾取自身中移除:

    for(int abc=0;abc<participants.Length;abc++)
    {
        //remove clone set
        Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
        dictionary.Remove(clonePair);
    }
    
    运行代码可以更好地说明这个概念

    演示:

    static void Main(string[] args)
    {
        //Create participants set
        string[] participants = {"James","John","Tyrone","Rebecca","Tiffany","Judith"};
    
        //Create not allowed lists
        string[] jamesNotAllowedList = {"Tiffany", "Tyrone"};
        string[] johnNotAllowedList = {};
        string[] tyroneNotAllowedList = {};
        string[] rebeccaNotAllowedList ={"James", "Tiffany"};
        string[] judithNotAllowedList = {};
        //Create list of not allowed lists
        string[][] notAllowedLists = { jamesNotAllowedList, johnNotAllowedList, tyroneNotAllowedList, rebeccaNotAllowedList, judithNotAllowedList};
    
        //Create dictionary<Tuple<string,string>, bool> from participants array by using cartesian join on itself
        Dictionary<Tuple<string, string>, bool> dictionary = participants.SelectMany(left => participants, (left, right) => new Tuple<string, string>(left, right)).ToDictionary(item=> item, item=>true);
    
        //Loop through each person who owns a notAllowedList 
        for (int list = 0; list < notAllowedLists.Length; list++)
        {
            //Loop through each name on the not allowed list
            for (int person = 0; person<notAllowedLists[list].Length; person++)
            {
                string personNotAllowing = participants[list];
                string notAllowedPerson = notAllowedLists[list][person];
                //Change the boolean value matched to the composite key
                dictionary[new Tuple<string, string>(personNotAllowing, notAllowedPerson)] = false;
                Console.WriteLine(personNotAllowing + " did not allow " + notAllowedPerson);
            }
        }                
    
        //Then since a participant cant pick itself
        for(int abc=0;abc<participants.Length;abc++)
        {
            //remove clone set
            Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
            dictionary.Remove(clonePair);
        }
    
        //Display whats going on with this Dictionary<Tuple<string,string>, bool>
        Console.WriteLine("--------Allowed?--Dictionary------------\n");
        Console.WriteLine(string.Join("  \n", dictionary));
        Console.WriteLine("----------------------------------------\n\n");
    
        //Create Random Object
        Random rand = new Random();
    
        //Now that the data is organized in a dictionary..
          //..Let's have random participants pick random participants
    
        //For this demonstration lets try it 10 times
        for (int i=0;i<20;i++)
        {
            //Create a new random participant
            int rNum = rand.Next(participants.Length);
            string randomParticipant = participants[rNum];
            //Random participant picks a random participant
            string partner = participants[rand.Next(participants.Length)];
    
            //Create composite key for the current pair
            Tuple<string, string> currentPair = Tuple.Create(partner,randomParticipant);
    
            //Check if it's a valid choice
            try
            {
                if (dictionary[currentPair])
                {
                    Console.WriteLine(randomParticipant + " tries to pick " + partner);
                    Console.WriteLine("Valid.\n");
                    //add to dictionary
                    for(int j=0; j<participants.Length;j++)
                    {
                        //Make the partner never be able to be picked again
                        Tuple<string, string> currentPair2 = Tuple.Create(partner, participants[j]);
                        try
                        {
                            dictionary[currentPair2] = false;
                        }
                        catch
                        {
    
                        }
                    }
    
                }
                else
                {
                    Console.WriteLine(randomParticipant + " tries to pick " + partner);
                    Console.WriteLine(">>>>>>>>Invalid.\n");
                }
            }
            catch
            {
                //otherwise exception happens because the random participant
                  //And its partner participant are the same person
    
                //You can also handle the random participant picking itself differently
                  //In this catch block
    
                //Make sure the loop continues as many times as necessary
                //by acting like this instance never existed
                i = i - 1;
            }
    
    
        }
    
    
        Console.ReadLine();
    
    }
    
    static void Main(字符串[]args)
    {
    //创建参与者集
    string[]参与者={“詹姆斯”、“约翰”、“泰龙”、“丽贝卡”、“蒂芙尼”、“朱迪思”};
    //创建不允许的列表
    字符串[]jamesNotAllowedList={“Tiffany”,“Tyrone”};
    字符串[]johnNotAllowedList={};
    字符串[]tyroneNotAllowedList={};
    字符串[]rebeccaNotAllowedList={“James”,“Tiffany”};
    字符串[]judithNotAllowedList={};
    //创建不允许列表的列表
    字符串[][]NotAllowedList={jamesNotAllowedList,johnNotAllowedList,TyronenNotAllowedList,rebeccaNotAllowedList,judithNotAllowedList};
    //通过对自身使用笛卡尔连接从参与者数组创建字典
    Dictionary Dictionary=participants.SelectMany(左=>participants,(左,右)=>newtuple(左,右)).ToDictionary(item=>item,item=>true);
    //循环浏览每个拥有不允许名单的人
    对于(int list=0;list对于(int person=0;person此代码将始终为您提供符合您的标准的输出:

    public static class Program
    {
    
        public static void Main(string[] args)
        {
            var gathering = new Gathering();
            gathering.MakeSelections();
    
            foreach (var item in gathering.participants)
            {
                Console.WriteLine(item.name + ":" + item.selectedParticipant);
            }
        }
    
        public class Participant
        {
            public string name;
            public List<string> exclusions;
            public string selectedParticipant;
        }
    
        public class Gathering
        {
            public List<Participant> participants;
            public List<string> availableParticipants;
            public List<string> usedNames;
            public Dictionary<string, string> result;
    
            public Gathering()
            {
                //initialize participants
                participants = new List<Participant>();
    
                participants.Add(new Participant
                {
                    name = "James",
                    exclusions = new List<string> { "Tiffany", "Tyrone" }
                });
    
                participants.Add(new Participant
                {
                    name = "John",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Judith",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Rebecca",
                    exclusions = new List<string> { "James", "Tiffany" }
                });
    
                participants.Add(new Participant
                {
                    name = "Tiffany",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Tyrone",
                    exclusions = new List<string> { }
                });
    
                //prevent participants from selecting themselves
                foreach (Participant p in participants)
                {
                    p.exclusions.Add(p.name);
                }
    
                //create list of all the names (all available participants at the beginning)
                availableParticipants = participants.Select(x => x.name).ToList();
    
            }
    
            public void MakeSelections()
            {
                Participant currentParticipant;
                Random randy = new Random();
    
    
                //Sort Participants by the length of their exclusion lists, in descending order.
                participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
    
                //Get the first participant in the list which hasn't selected someone yet
                currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
    
                while (currentParticipant != null)
                {
                    //of the available participants, create a list to choose from for the current participant
                    List<string> listToChooseFrom = availableParticipants.Where(x => !currentParticipant.exclusions.Contains(x)).ToList();
    
                    //select a random participant from the list of eligible ones to be matched with the current participant
                    string assignee = listToChooseFrom[randy.Next(listToChooseFrom.Count)];
                    currentParticipant.selectedParticipant = assignee;
    
                    //remove the selected participant from the list of available participants
                    availableParticipants.RemoveAt(availableParticipants.IndexOf(assignee));
    
                    //remove the selected participant from everyone's exclusion lists
                    foreach (Participant p in participants)
                        if (p.exclusions.Contains(assignee))
                            p.exclusions.RemoveAt(p.exclusions.IndexOf(assignee));
    
                    //Resort Participants by the length of their exclusion lists, in descending order.
                    participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
    
                    //Get the first participant in the list which hasn't selected someone yet
                    currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
                }
    
                //finally, sort by alphabetical order
                participants.Sort((p1, p2) => p1.name.CompareTo(p2.name));
    
            }
        }
    }
    
    公共静态类程序
    {
    公共静态void Main(字符串[]args)
    {
    var-collection=新聚集();
    granning.MakeSelections();
    foreach(gathering.participants中的变量项)
    {
    Console.WriteLine(item.name+“:”+item.selectedParticipant);
    }
    }
    公开课参与者
    {
    公共字符串名称;
    公开名单排除;
    公共字符串selectedParticipant;
    }
    公开班级聚会
    {
    公开名单参与者;
    可获得的公共参与人名单;
    使用名称的公共列表;
    公共词典结果;
    公众集会()
    {
    //初始化参与者
    参与者=新列表();
    参与者。添加(新参与者)
    {
    name=“詹姆斯”,
    排除=新列表{“Tiffany”、“Tyrone”}
    });
    参与者。添加(新参与者)
    {
    name=“John”,
    排除项=新列表{}
    });
    参与者。添加(新参与者)
    {
    name=“Judith”,
    排除项=新列表{}
    });
    参与者。添加(新参与者)
    {
    name=“Rebecca”,
    排除=新列表{“James”,“Tiffany”}
    });
    参与者。添加(新参与者)
    {
    name=“Tiffany”,
    排除项=新列表{}
    });
    参与者。添加(新参与者)
    {
    name=“Tyrone”,
    排除项=新列表{}
    });
    //阻止参与者选择自己
    foreach(参与者中的参与者p)
    {
    p、 除外条款。添加(p.名称);
    }
    //创建所有姓名的列表(开头的所有可用参与者)
    availableParticipants=participants.Select(x=>x.name).ToList();
    }
    公共void MakeSelections()
    {
    参与者当前参与者;
    随机随机数=新随机数();
    //按排除列表的长度按降序对参与者进行排序。
    排序((p1,p2)=>p2.Exclutions.Count.CompareTo(p1.Exclutions.Count));
    //获取列表中尚未选择某人的第一个参与者
    currentParticipant=participants.FirstOrDefault(p=>p.selectedParticipant==null);
    while(currentParticipant!=null)
    {
    //在可用参与者中,为当前参与者创建一个可供选择的列表
    List listToChooseFrom=availableParticipants.Where(x=>!currentParticipant.Exclutions.Contains(x)).ToList();
    //从符合条件的参与者列表中随机选择要与当前参与者匹配的参与者
    字符串assignee=listToChooseFrom[randy.Next(listToChooseFrom.Count)];
    currentParticipant.selectedParticipant=受让人;
    //从可用参与者列表中删除所选参与者
    可用参与人。RemoveAt(可用参与人。索引(受让人));
    //从每个人的排除列表中删除所选参与者
    foreach(参与者中的参与者p)
    
    for(int abc=0;abc<participants.Length;abc++)
    {
        //remove clone set
        Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
        dictionary.Remove(clonePair);
    }
    
    for(int abc=0;abc<participants.Length;abc++)
    {
        dictionary[Tuple.Create(participants[abc],participants[abc])] = false;
    }
    
     for(int j=0; j<participants.Length;j++)
     {
         //Make the partner never be able to be picked again
         Tuple<string, string> currentPair2 = Tuple.Create(partner, participants[j]);
         try
         {
             dictionary[currentPair2] = false;
         }
         catch
         {
         }
    }
    
    static void Main(string[] args)
    {
        //Create participants set
        string[] participants = {"James","John","Tyrone","Rebecca","Tiffany","Judith"};
    
        //Create not allowed lists
        string[] jamesNotAllowedList = {"Tiffany", "Tyrone"};
        string[] johnNotAllowedList = {};
        string[] tyroneNotAllowedList = {};
        string[] rebeccaNotAllowedList ={"James", "Tiffany"};
        string[] judithNotAllowedList = {};
        //Create list of not allowed lists
        string[][] notAllowedLists = { jamesNotAllowedList, johnNotAllowedList, tyroneNotAllowedList, rebeccaNotAllowedList, judithNotAllowedList};
    
        //Create dictionary<Tuple<string,string>, bool> from participants array by using cartesian join on itself
        Dictionary<Tuple<string, string>, bool> dictionary = participants.SelectMany(left => participants, (left, right) => new Tuple<string, string>(left, right)).ToDictionary(item=> item, item=>true);
    
        //Loop through each person who owns a notAllowedList 
        for (int list = 0; list < notAllowedLists.Length; list++)
        {
            //Loop through each name on the not allowed list
            for (int person = 0; person<notAllowedLists[list].Length; person++)
            {
                string personNotAllowing = participants[list];
                string notAllowedPerson = notAllowedLists[list][person];
                //Change the boolean value matched to the composite key
                dictionary[new Tuple<string, string>(personNotAllowing, notAllowedPerson)] = false;
                Console.WriteLine(personNotAllowing + " did not allow " + notAllowedPerson);
            }
        }                
    
        //Then since a participant cant pick itself
        for(int abc=0;abc<participants.Length;abc++)
        {
            //remove clone set
            Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
            dictionary.Remove(clonePair);
        }
    
        //Display whats going on with this Dictionary<Tuple<string,string>, bool>
        Console.WriteLine("--------Allowed?--Dictionary------------\n");
        Console.WriteLine(string.Join("  \n", dictionary));
        Console.WriteLine("----------------------------------------\n\n");
    
        //Create Random Object
        Random rand = new Random();
    
        //Now that the data is organized in a dictionary..
          //..Let's have random participants pick random participants
    
        //For this demonstration lets try it 10 times
        for (int i=0;i<20;i++)
        {
            //Create a new random participant
            int rNum = rand.Next(participants.Length);
            string randomParticipant = participants[rNum];
            //Random participant picks a random participant
            string partner = participants[rand.Next(participants.Length)];
    
            //Create composite key for the current pair
            Tuple<string, string> currentPair = Tuple.Create(partner,randomParticipant);
    
            //Check if it's a valid choice
            try
            {
                if (dictionary[currentPair])
                {
                    Console.WriteLine(randomParticipant + " tries to pick " + partner);
                    Console.WriteLine("Valid.\n");
                    //add to dictionary
                    for(int j=0; j<participants.Length;j++)
                    {
                        //Make the partner never be able to be picked again
                        Tuple<string, string> currentPair2 = Tuple.Create(partner, participants[j]);
                        try
                        {
                            dictionary[currentPair2] = false;
                        }
                        catch
                        {
    
                        }
                    }
    
                }
                else
                {
                    Console.WriteLine(randomParticipant + " tries to pick " + partner);
                    Console.WriteLine(">>>>>>>>Invalid.\n");
                }
            }
            catch
            {
                //otherwise exception happens because the random participant
                  //And its partner participant are the same person
    
                //You can also handle the random participant picking itself differently
                  //In this catch block
    
                //Make sure the loop continues as many times as necessary
                //by acting like this instance never existed
                i = i - 1;
            }
    
    
        }
    
    
        Console.ReadLine();
    
    }
    
    public static class Program
    {
    
        public static void Main(string[] args)
        {
            var gathering = new Gathering();
            gathering.MakeSelections();
    
            foreach (var item in gathering.participants)
            {
                Console.WriteLine(item.name + ":" + item.selectedParticipant);
            }
        }
    
        public class Participant
        {
            public string name;
            public List<string> exclusions;
            public string selectedParticipant;
        }
    
        public class Gathering
        {
            public List<Participant> participants;
            public List<string> availableParticipants;
            public List<string> usedNames;
            public Dictionary<string, string> result;
    
            public Gathering()
            {
                //initialize participants
                participants = new List<Participant>();
    
                participants.Add(new Participant
                {
                    name = "James",
                    exclusions = new List<string> { "Tiffany", "Tyrone" }
                });
    
                participants.Add(new Participant
                {
                    name = "John",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Judith",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Rebecca",
                    exclusions = new List<string> { "James", "Tiffany" }
                });
    
                participants.Add(new Participant
                {
                    name = "Tiffany",
                    exclusions = new List<string> { }
                });
    
                participants.Add(new Participant
                {
                    name = "Tyrone",
                    exclusions = new List<string> { }
                });
    
                //prevent participants from selecting themselves
                foreach (Participant p in participants)
                {
                    p.exclusions.Add(p.name);
                }
    
                //create list of all the names (all available participants at the beginning)
                availableParticipants = participants.Select(x => x.name).ToList();
    
            }
    
            public void MakeSelections()
            {
                Participant currentParticipant;
                Random randy = new Random();
    
    
                //Sort Participants by the length of their exclusion lists, in descending order.
                participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
    
                //Get the first participant in the list which hasn't selected someone yet
                currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
    
                while (currentParticipant != null)
                {
                    //of the available participants, create a list to choose from for the current participant
                    List<string> listToChooseFrom = availableParticipants.Where(x => !currentParticipant.exclusions.Contains(x)).ToList();
    
                    //select a random participant from the list of eligible ones to be matched with the current participant
                    string assignee = listToChooseFrom[randy.Next(listToChooseFrom.Count)];
                    currentParticipant.selectedParticipant = assignee;
    
                    //remove the selected participant from the list of available participants
                    availableParticipants.RemoveAt(availableParticipants.IndexOf(assignee));
    
                    //remove the selected participant from everyone's exclusion lists
                    foreach (Participant p in participants)
                        if (p.exclusions.Contains(assignee))
                            p.exclusions.RemoveAt(p.exclusions.IndexOf(assignee));
    
                    //Resort Participants by the length of their exclusion lists, in descending order.
                    participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
    
                    //Get the first participant in the list which hasn't selected someone yet
                    currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
                }
    
                //finally, sort by alphabetical order
                participants.Sort((p1, p2) => p1.name.CompareTo(p2.name));
    
            }
        }
    }
    
    string[] source = { "A", "B", "C", "D", "E", "F" };
    string[] picked = source.ToArray(); // copy
    var rand = new Random();
    
    for (int i = source.Length - 1, r; i > 0; --i)
    {
        var pick = picked[r = rand.Next(i)];    // pick random item less than the current one 
        picked[r] = picked[i];                  // and swap with the current one
        picked[i] = pick;
    
        Console.WriteLine(i + " swapped with " + r);
    }
    
    Console.WriteLine("\nsource: " + string.Join(", ", source) + 
                      "\npicked: " + string.Join(", ", picked));
    
    5 swapped with 4
    4 swapped with 2
    3 swapped with 0
    2 swapped with 1
    1 swapped with 0
    
    source: A, B, C, D, E, F
    picked: F, D, B, A, C, E