Reputation: 517
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
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
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