Stephen Johnson
Stephen Johnson

Reputation: 517

Shuffle List of strings, but not too much

I have a list of strings in C# such as:

List<string> myList;

Lets say I populate it by adding 20 strings, starting from "1", up to "20".

myList.Add("1"); // And so on...

How can I, in the most efficient and elegant way, randomly shuffle this list of strings while restricting how far each item of the list can end up from it's original index to, say, 4 .

Example of what I want:

I want the order:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

For example, to be shuffled to the following:

2 5 4 3 6 1 8 7 10 9 12 11 15 14 13 16 18 15 20 19

One (straightforward) way of doing it would be to split the list into four parts and shuffle the parts separately. But I am still not sure how efficient this would be.

Efficiency in my case means not doing something that is overcomplicated or just stupid.

Upvotes: 2

Views: 113

Answers (2)

Ofir Winegarten
Ofir Winegarten

Reputation: 9365

The following Linq will create a new index where the new index is limited to distance places away from original index

List<string> list = Enumerable.Range(1, 20).Select(i => i.ToString()).ToList();
Random rng = new Random();
int distance = 4;

List<string> newList = list
    .Select((s, i) => 
        new {OrigIndex = i, NewIndex = i + rng.Next(-distance, distance+1), Val = s})
    .OrderBy(a => a.NewIndex).ThenBy(a=>a.OrigIndex)
    .Select(a => a.Val)
    .ToList();  

Upvotes: 1

Thomas Ayoub
Thomas Ayoub

Reputation: 29431

You can use the following code:

List<int> myList = Enumerable.Range(1, 20).ToList(); // Feed the list from 1 to 20

int numberByGroups = 4;
List<int> result = new List<int>();

for (int skip = 0; skip < myList.Count; skip = skip + numberByGroups)
{
    result.AddRange(myList.Skip(skip) // skip the already used numbers
                          .Take(numberByGroups) // create a group
                          .OrderBy(a => Guid.NewGuid()) // "Shuffle"
                          .ToList());
}

Console.WriteLine(String.Join(", ", result));

Which will shuffle by groups of numberByGroups

Upvotes: 0

Related Questions