2011-01-19 9 views
10

Chcę wiedzieć Shuffle StringShuffle ciąg C#

Przykład ciąg

string word; 

//I want to shuffle it 
word = "hello" 

byłbym w stanie dostać:

rand == "ohlel" 
rand == "lleho" 
etc. 

Odpowiedz

5

Patrzysz na coś jak Fisher–Yates shuffle . Jest rzeczywiście przykładem Python na tej stronie:

import random 

def shuffle(x): 
    for i in reversed(range(1, len(x))): 
     # pick an element in x[:i+1] with which to exchange x[i] 
     j = random.randrange(i+1) 
     x[i], x[j] = x[j], x[i] 

Edycja: Ponieważ pytanie jest oznaczone zarówno ironpython i c#, tam także przykład Java, który jest tam bardzo łatwo przekształcić w C#.

5

C#:

string str = "hello"; 

// The random number sequence 
Random num = new Random(); 

// Create new string from the reordered char array 
string rand = new string(str.ToCharArray(). 
       OrderBy(s => (num.Next(2) % 2) == 0).ToArray()); 
+8

To nie przyniesie dobrego wyniku losowego. Zgodnie z MSDN OrderBy użyje stabilnego sortowania i zachowa kolejność dla tych znaków, które mają tę samą wartość. Aby "h" w "cześć" zostało umieszczone jako ostatnie, "h" musi być "fałszywe", a pozostałe "prawdziwe". Jednak wynik będzie "elloh", co nie jest zbyt ekscytujące. http://msdn.microsoft.com/en-us/library/bb534966.aspx –

9

To rozwiązanie (w formie metodę rozszerzenia) jest ładny:

public static string Shuffle(this string str) 
    { 
     char[] array = str.ToCharArray(); 
     Random rng = new Random(); 
     int n = array.Length; 
     while (n > 1) 
     { 
      n--; 
      int k = rng.Next(n + 1); 
      var value = array[k]; 
      array[k] = array[n]; 
      array[n] = value; 
     } 
     return new string(array); 
    } 
+0

To nie jest jednolity shufflw – Paparazzi

0
class Program 
{ 

    static void Main(string[] args) 
    { 
     string word = "hello"; 
     string temp = word; 
     string result = string.Empty; 
     Random rand = new Random(); 

     for (int a = 0; a < word.Length; a++) 
     { 
      //multiplied by a number to get a better result, it was less likely for the last index to be picked 
      int temp1 = rand.Next(0, (temp.Length - 1) * 3); 

      result += temp[temp1 % temp.Length]; 
      temp = temp.Remove(temp1 % temp.Length, 1); 
     } 
     Console.WriteLine(result); 
    } 
} 
0

Można by spróbować coś takiego ..

class Program 
{ 
    static bool IsPositionfilled(int Position, List<int> WordPositions) 
    { 
     return WordPositions.Exists(a => a == Position); 
    } 

    public static string shufflestring(string word) 
    { 
     List<int> WordPositions = new List<int>(); 
     Random r = new Random(); 
     string shuffledstring = null; 
     foreach (char c in word) 
     { 
      while (true) 
      { 

       int position = r.Next(word.Length); 
       if (!IsPositionfilled(position, WordPositions)) 
       { 
        shuffledstring += word[position]; 
        WordPositions.Add(position); 
        break; 
       } 
      } 


     } 
     return shuffledstring; 
    } 
    static void Main(string[] args) 
    { 

     string word = "Hel"; 
     Hashtable h = new Hashtable(); 
     for (int count = 0; count < 1000; count++) 
     { 
      Thread.Sleep(1); 
      string shuffledstring = shufflestring(word); 
      if (h.Contains(shuffledstring)) 
       h[shuffledstring] = ((int)h[shuffledstring]) + 1; 
      else 
       h.Add(shuffledstring,1); 
     } 

     Console.WriteLine(word); 
     foreach (DictionaryEntry e in h) 
     { 
      Console.WriteLine(e.Key.ToString() + " , " + e.Value.ToString()); 
     } 
    } 
} 
1

inspirowane tsql 'zamów przez newid()

static string shuffle(string input) 
{ 
    var q = from c in input.ToCharArray() 
      orderby Guid.NewGuid() 
      select c; 
    string s = string.Empty; 
    foreach (var r in q) 
     s += r; 
    return s; 
} 
+0

newid jest wyjątkowy nie losowy – Paparazzi

-1

Próbowałem starego sposobu, aby to zrobić, ten działa dobrze.

static void Main() 
    {   
     string input = "hello"; 
     string output = ""; 
     int ranIndex = 0; 
     List<int> indexes = new List<int>(); 
     char[] split = input.ToCharArray(); 
     Random ran = new Random(); 

     for (int i = 0; i < input.Length; i++) 
     { 
      ranIndex = ran.Next(0, input.Length); 

      if (!indexes.Contains(ranIndex)) 
      { 
       indexes.Add(ranIndex); 
      } 
      else 
      { 
       i--; 
      } 
     } 

     foreach (int value in indexes) 
     { 
      output += split[value]; 
     } 

      Console.WriteLine(output); 
      Console.ReadLine(); 
    } 
+0

dlaczego głosowanie w dół? – Rye

1

Najlepszym sposobem, aby przetasować ciąg lub listę ciągów korzysta w ten sposób. Tutaj dostaniesz żadnych duplikatów:

class CardsDeck 
{ 
    public static Random r = new Random(); 

    private static List<string> cards = new List<string>{ "♣ King", "♣ Queen", "♣ Jack", " ♣", "♣ 7", "♣ 8", "♣ 9", "♣ 10", 
                  "♦ King", "♦ Queen", "♦ Jack", " ♦", "♦ 7", "♦ 8", "♦ 9", "♦ 10", 
                  "♥ King", "♥ Queen", "♥ Jack", " ♥", "♥ 7", "♥ 8", "♥ 9", "♥ 10", 
                  "♠ King", "♠ Queen", "♠ Jack", " ♠", "♠ 7", "♠ 8", "♠ 9", "♠ 10" }; 
    public string ReceiveCards() 
    { 
     if (cards.Count > 0) 
     { 
      int index = r.Next(cards.Count); 
      var card = cards[index]; 
      cards.RemoveAt(index); 
      return card; 
     } 
     else 
     { 
      return ""; 
     } 
    } 
} 
+1

Nie, to nie jest najlepszy sposób. Mimo że unika duplikatów, jest to bardzo nieefektywne. Wymieszanie Fisher-Yates wspomniane w innym miejscu jest o wiele lepszym sposobem na zrobienie tego. –

0

to osiągnąć z tego rozszerzenia:

public static class Extensions{ 
    public static string Scramble(this string s){ 
     return new string(s.ToCharArray().OrderBy(x=>Guid.NewGuid()).ToArray()); 
    } 
} 
+0

Poważnie, chciałbym wiedzieć, co jest z tym nie tak. Jest dość szybki, ma jedną linię i jest łatwy do odczytania i działa. – PRMan

+0

GUID jest unikalny nie losowy – Paparazzi

2

Try Fisher-Yates shuffle

class Shuffle 
{ 
    static System.Random rnd = new System.Random(); 

    static void Fisher_Yates(int[] array) 
    { 
     int arraysize = array.Length; 
     int random; 
     int temp; 

     for (int i = 0; i < arraysize; i++) 
     { 
      random = i + (int)(rnd.NextDouble() * (arraysize - i)); 

      temp = array[random]; 
      array[random] = array[i]; 
      array[i] = temp; 
     } 
    } 

    public static string StringMixer(string s) 
    { 
     string output = ""; 
     int arraysize = s.Length; 
     int[] randomArray = new int[arraysize]; 

     for (int i = 0; i < arraysize; i++) 
     { 
      randomArray[i] = i; 
     } 

     Fisher_Yates(randomArray); 

     for (int i = 0; i < arraysize; i++) 
     { 
      output += s[randomArray[i]]; 
     } 

     return output; 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     string original = "Hello World!"; 

     string mixedOriginal = Shuffle.StringMixer(original); 

     System.Console.WriteLine("The original string: {0}", original); 
     System.Console.WriteLine("A mix of characters from the original string: {0}", mixedOriginal); 

     System.Console.ReadKey(); 
    } 
} 
+0

To działało świetnie, dziękuję. –

-1

Fisher-Yates

static Random rand = new Random(); 
public static string ShuffleString(string s) 
{ 
    if (string.IsNullOrEmpty(s)) 
     return s; 
    char[] chars = s.ToCharArray(); 
    char c; 
    int j; 
    for(int i = chars.Length - 1; i > 0; i--) 
    { 
     j = rand.Next(i + 1); // Next max is exclusive 
     if (j == i) 
      continue; 
     c = chars[j]; 
     chars[j] = chars[i]; 
     chars[i] = c; 
    } 
    return chars.ToString(); 
} 
+0

Działa dobrze, oprócz 'chars.ToString()' zawsze zwraca literał "System.Char []". Linia 'zwraca znaki.ToString(); 'powinno być' return new string (chars); ' –

+0

To nie zachowuje oryginalnego zestawu, nadpisuje znaki nieużywane. –