0

Lets say I have an array of integers. I found out that I can randomize the order of the elements simply by doing:

Random rnd = new Random();
array = array.OrderBy(x => rnd.Next()).ToArray();

But lets say I want to keep the first and the last elements in their original place. Can I do it using the same approach (using OrderBy()) or do I need to re-think my situation?

1
  • There might be a cleaner solution, but just save the first and last elements and then reinsert them in the randomized list. Commented Feb 9, 2017 at 13:17

5 Answers 5

1

You can't do that in a single expression, but maybe a List<int> could help:

Random rnd = new Random();
var list = new List<int>();
list.Add(array[0]);
var partialArray = array.Skip(1).Take(array.Length - 2);
list.AddRange(partialArray.OrderBy(x => rnd.Next()));
list.Add(array[array.Length -1 ]);
Sign up to request clarification or add additional context in comments.

Comments

1

You can do it:

        int[] ints = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        ints = ints.Select((x, index) => new { Value = x, Index = index })
               .OrderBy(tuple => (tuple.Index >= start && tuple.Index <= stop) ? random.Next(start, stop) : tuple.Index)
               .Select(tuple => tuple.Value)
               .ToArray();

Comments

1

Of course you can use the same approach, but you have to take care of the first and the last value. Just an example for your input array:

var list = array.Skip(1).Take(array.Length - 2).OrderBy(x => rnd.Next()).ToList();
list.Insert(0, array.First());
list.Add(array.Last());
array = list.ToArray();

Dmitry's example is basically the same, but gives you the option to keep more elements.

1 Comment

Dang, too slow, I had written almost the exact same thing character by character!
1

You can just use a standard shuffle algorithm modified to use a range, for example (using the Fisher-Yates algorithm):

public static void Shuffle<T>(IList<T> array, Random rng, int start, int end)
{
    for (int n = end+1; n > start+1;)
    {
        int k = rng.Next(start, n);
        --n;
        T temp = array[n];
        array[n] = array[k];
        array[k] = temp;
    }
}

Then call it like this:

Random rng = new Random();

for (int i = 0; i < 100; ++i)
{
    var array = Enumerable.Range(1, 12).ToArray();
    Shuffle(array, rng, 3, 9);
    Console.WriteLine(string.Join(", ", array));
}

Comments

0

A slightly different approach which doesn't involve using List....

        Random rnd = new Random();
        //array = array.OrderBy(x => rnd.Next()).ToArray();

        int lastIndexToChange = array.Length - 1;

        for (int i = 1; i < lastIndexToChange; i++)
        {
            var tempStore = array[i];
            int newPosition = rnd.Next(1, lastIndexToChange);

            array[i] = array[newPosition];
            array[newPosition] = tempStore;
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.