2017-12-09 7 views
3

イム選ぶ:除外して一覧<string>からランダムな文字列を選択し、非反復ユーザー聞かせプログラムの書き込みしようとして

  1. は、文字列のセットをロードします。
  2. セットをループし、同じセットから別のストリングを選択します。
  3. 選択された文字列が再度選択されないようにします。
  4. 特定の文字列を指定することができないようにしました。

    enter image description here

    そしてテーブルの下のサンプルシナリオされています:私はこの簡単な方法を行うことになっていますどのように

    enter image description here

例は、テーブルの下にありますか?

私は以下のコードを持っていますが、何も残されていない場合はすべてを再起動するので、有効なセットを生成するのは永遠のようです。

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 

Participantクラスは、これらのプロパティで構成されています:

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

ParticipantPickクラスは、これらのプロパティで構成されています:

public string Participant { get; set; } 
public string PickedParticipant { get; set; } 
public string Number { get; set; } 
+1

誰が誰を選ぶことができ、誰が選ぶことができないの基準は何ですか?なぜジェームズはタイロンを選ぶことができないはずですか?これに対してどのようなコードを書いたのですか?そのコードを共有してください。 –

+0

'picks 'のリストを作成するときに、ランダムなものを選ぶ前に*除外してみてはどうでしょうか?それはいくつかの再起動を排除する必要があります –

+0

'p.Name!= participant.Name'と'!Utilities.IsInList(p.Name、pickedParticipantNames) 'で何をやっているのでしょうか? 'Utilities.IsInList(string ref、IEnumerable ソース)'は基本的に 'source'をチェックします。' ref'はその内部のどこかに存在し、ブール値のデータを返します。 – Nii

答えて

1

使用して、これはdictionaryを使用することです解決することができる一つの方法tupleとデータ型boolの一致する値の複合キー。

Dictionary<Tuple<string, string>, bool> 

複合キーTuple<sring,string>は、参加者のすべての順列が含まれていますし、その適切なbool値にそれらを一致させます。

例えば、のような値で満たさ辞書:

Dictionary<Tuple<"Judith","James">, true> 

は...ジュディスはジェームズを選ぶことは有効であることを示すであろう。

参加者の可能な組み合わせごとに辞書を作成し、その値をtrueに設定すると、プログラムの開始時に有効になります。

これはcartesian join using an array with itselfによって達成できます。

Dictionary<Tuple<string, string>, bool> dictionary = participants.SelectMany(left => participants, (left, right) => new Tuple<string, string>(left, right)).ToDictionary(item=> item, item=>true); 

可能ピックのすべての順列を取得し、trueにそれらを設定した後、我々はリストにし、falseにその複合キー用の辞書値を変更する「選択することは許されない」を通過することができます。

dictionary[new Tuple<string, string>(personNotAllowing, notAllowedPerson)] = false; 

あなたは次のようにループを使用して自分自身を選んでから参加者を削除することができます。

for(int abc=0;abc<participants.Length;abc++) 
{ 
    //remove clone set 
    Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]); 
    dictionary.Remove(clonePair); 
} 

それとも単にfalseにクローンペアの値を変更することもできます。このプログラム例で

for(int abc=0;abc<participants.Length;abc++) 
{ 
    dictionary[Tuple.Create(participants[abc],participants[abc])] = false; 
} 

、私は参加者のstring[]を作成し、それらが許可されていない人々のそれぞれのリストのためのstring[]。次に私はデカルト結合を行い、参加者の配列はとなり、となります。これにより、すべての置換が行われ、初期値はtrueブール値になります。

私は参加者が偽に許可されていない辞書を変更し、例辞書を表示します。

その後、他のランダム参加者を選んで妥当であるかどうかをテストするランダム参加者のインスタンスを10個作成します。

参加者が別の参加者を選ぶたびに、その複合キーをチェックして、値がtrueであるかどうかを調べます。

結果が有効な場合は、得られた参加者のすべての組み合わせがに設定され、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(); 

} 
+0

それぞれの_notAllowedListを作成する部分で、これが実行時に実行できると想定するのは安全でしょうか?もちろん、ジェイムズと残りは必ずしも参加者になるとは限らず、その数は増減する可能性があります。 – Nii

+0

@Nii辞書はその中のエントリを変更する前に作成されます。私はコードを1行に最小限に抑えましたが、基本的には参加者のすべての可能な組み合わせを* default *で 'true'の値を持つキーとして作成します。辞書は '4,294,967,296'キーのどこかに格納することができます。だからこそ、あなたは微妙な量の参加者がいない限り、理論的にはうまくいくはずです。各notAllowedListを作成する部分では、基本的に 'notAllowedLists'の' notAllowedList'を使ってそれぞれの人をループさせ、その項目を 'false'の値に設定します。 – Jamin

0

このコードは、常にあなたの基準に準拠して、あなたの出力が得られます:簡単なバージョンで

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

     } 
    } 
} 
0

を、項目だけでシャッフルすることができます。

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 

、またはソースを任意にシャッフルすることができ、各人物がリスト内の次の人物を選ぶことができます。

関連する問題