Mi1anovic
Mi1anovic

Reputation: 477

How to keep all characters in random?

I have input from textbox let´s say "abc". I want from random to randomize characters from this input. I can do that but from here I don´t know how to code to randomize only with all characters in final. So random final should be only one of these: "abc" "acb "bac" "bca" "cab" "cba". Now I have output like "abb" "ccc" "bba".

Random random = new Random();
int _length = _input.Length;
return new string(Enumerable.Repeat(_input, _length)
                 .Select(s => s[random.Next(s.Length)]).ToArray());

Upvotes: 0

Views: 143

Answers (4)

Harald Coppoolse
Harald Coppoolse

Reputation: 30464

Use the modern version of the Fisher-Yates shuffle

From Wikipedia: The Fisher–Yates shuffle is an algorithm for generating a random permutation of a finite sequence — in plain terms, the algorithm shuffles the sequence

The following is implemented as extension function, so you can use it in a concatenation of LINQ statements:

private static readonly Random rnd = new Random();
public static IEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source)
{
    // TODO: exception if source equals null

    // copy the source items to a new List, we don't want to shuffle the input, do we?
    List<TSource> sourceItems = source.ToList();
    int lastIndex = sourceItems.Count-1;
    for (int i = 0; i < lastIndex; ++i)
    {
        // pick an index number on or after i
        // if the picked number equals i, then do not shuffle element [i]
        int j = rnd.Next(i, sourceItems.Count);
        if (i != j)
        {   // swap:
            var tmp = sourceItems[i];
            sourceItems[i] = sourceItems[j];
            sourceItems[j] = tmp;
        }
        // yield return the next element of the shuffled sequence
        yield return sourceItems[i];
    }
}

usage:

List<MyClass> input = ...
IEnumerable<MyClass> output = input.Shuffle();

Note that the input is not shuffled.

The nice thing is, that if you only want a few outputs, no more items are shuffled then necessarry. The following will only take 3 elements from your original list:

var output = Enumerable.Range(0, 10)
    .Shuffle()
    .Take(3)
    .ToList();

output is 3 distinct random numbers between 0 and 9

Upvotes: 0

vc 74
vc 74

Reputation: 38179

Sorting the letters by random:

var random = new Random();

var randomized = new string(_input.OrderBy(letter => random.Next()).ToArray());

Should do it

Link to fiddle

Upvotes: 3

Soufiane Tahiri
Soufiane Tahiri

Reputation: 181

You seem looking for a shuffling method :

string s = "abc";
      char[] ar = s.ToCharArray();
    Random rnd = new Random();
    int n = ar.Length;
    while (n > 1)
    {
        n--;
        int k = rnd.Next(n + 1);
        var x = ar[k];
        ar[k] = ar[n];
        ar[n] = x;
    }
    string result=  new string(ar);

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062780

One way to do this would be to create a list of the input characters, and select random elements, removing them each time. Otherwise, you need to track which ones you've "used", etc.

For example:

    string s = "abc";
    var candidates = new List<char>(s); // the as-yet-unused data
    var result = new char[s.Length];
    var random = new Random();
    for(int i = 0; i < result.Length; i++)
    {
        int index = random.Next(candidates.Count); // pick an unused element
        result[i] = candidates[index];
        candidates.RemoveAt(index); // remove, so we don't repeat it
    }
    string final = new string(result);

Upvotes: 2

Related Questions