Shuffle string c#
I want to know shuffle string
Example string
string word;
//I want to shuffle it
word = "开发者_运维问答hello"
I would be able to get:
rand == "ohlel"
rand == "lleho"
etc.
This solution (in a form of extension method) is nice:
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);
}
I accomplish this with this extension:
public static class Extensions{
public static string Scramble(this string s){
return new string(s.ToCharArray().OrderBy(x=>Guid.NewGuid()).ToArray());
}
}
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());
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();
}
}
You're looking for something like the Fisher–Yates shuffle. There's actually a Python example on that page:
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]
Edit: Since your question is tagged both ironpython
and c#
, there's also a Java example there which is very easily converted to C#.
One thing to be aware of is that the input string may contain things like surrogate pairs and combining diacritics. If these are a concern, you may want to try shuffling text elements:
using System;
using System.Globalization;
using System.Linq;
using System.Text;
public static class StringExtensions
{
public static string ShuffleByTextElements(this string source, Random random)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (random == null) throw new ArgumentNullException(nameof(random));
var info = new StringInfo(source);
var indices = Enumerable.Range(0, info.LengthInTextElements).ToArray();
// Fisher-Yates shuffle
for (var i = indices.Length; i-- > 1;)
{
var j = random.Next(i + 1);
if (i != j)
{
var temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}
}
var builder = new StringBuilder(source.Length);
foreach (var index in indices)
{
builder.Append(info.SubstringByTextElements(index, 1));
}
return builder.ToString();
}
}
Note that the above code will still not handle certain Unicode features such as bidirectional overrides correctly, nor will it handle the details of certain scripts where the letter form depends on where it is in the word. An example of this would be Greek lowercase sigma, which is encoded as U+03C3 GREEK SMALL LETTER SIGMA (σ), except at the end of the word where U+03C2 GREEK SMALL LETTER FINAL SIGMA (ς) is used instead.
inspired from tsql' order by 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;
}
The best way to shuffle a string or a list of strings is using this way. Here you will get no duplicates:
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 "";
}
}
}
You could try some thing like this..
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());
}
}
}
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);
}
}
Here is a solution that has already been posted, only the code is shorter and Random
as static variable.
private static Random rnd = new Random();
public static string Shuffle(this string str)
{
char[] array = str.ToCharArray();
int n = array.Length;
while (n > 1)
{
n--;
int k = rnd.Next(n + 1);
(array[n], array[k]) = (array[k], array[n]);
}
return new string(array);
}
I tried the old school way of doing it, this one works fine.
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();
}
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();
}
精彩评论