using System.Collections.Generic;
namespace ShuffleCharacters
public static class StringExtension
public static string ShuffleChars(string source, int count)
var shuffleMap = CalculateShuffleMap(source, count);
var sourceCharArray = source.ToCharArray();
var resultChars = Shuffle(shuffleMap, sourceCharArray);
var charsList = new List<char>(resultChars);
var charsArray = charsList.ToArray();
var resultString = new string(charsArray);
private static int[] CalculateShuffleMap(string source, int count)
var length = source.Length;
var baseMap = CreateMap(length);
var sourceMap = new int[length];
var resultMap = new int[length];
Array.Copy(baseMap, resultMap, length);
for (var i = 1; i < count; i++)
SwapAndShuffle(baseMap, ref sourceMap, ref resultMap);
var sameAsBase = IsEquals(baseMap, resultMap);
var mapShuffleCountReminder = count % mapRepeatPeriod;
for (var i = 1; i < mapShuffleCountReminder; i++)
SwapAndShuffle(baseMap, ref sourceMap, ref resultMap);
private static void SwapAndShuffle(int[] baseMap, ref int[] sourceMap, ref int[] targetMap)
Shuffle(baseMap, sourceMap, targetMap);
private static bool IsEquals<T>(IEnumerable<T> a, IEnumerable<T> b)
var aEnumerator = a.GetEnumerator();
var bEnumerator = b.GetEnumerator();
while (aEnumerator.MoveNext() && bEnumerator.MoveNext())
if (!aEnumerator.Current.Equals(bEnumerator.Current))
var bothFinished = !aEnumerator.MoveNext() && !bEnumerator.MoveNext();
private static void Shuffle<T>(IEnumerable<int> map, T[] sourceItems, T[] targetItems)
foreach (var sourceIndex in map)
targetItems[i] = sourceItems[sourceIndex];
private static IEnumerable<T> Shuffle<T>(IEnumerable<int> map, T[] items)
foreach (var sourceIndex in map)
yield return items[sourceIndex];
private static int[] CreateMap(int length)
var map = new int[length];
var middle = (length + 1) / 2;
for (var i = 0; i < middle; i++)
for (var i = middle; i < length; i++)
map[i] = (i - middle) * 2 + 1;