如何打乱子串

How to shuffle a substring

我有一个字符串 s,大小为 kn

我想随机播放 k n 大小的 s 块(给定 kn).

示例:s = abcdabcdabcdn = 4, k = 3.

BEGIN: abcdabcdabcd

 abcd       abcd       abcd
 └─┬─┘      └─┬─┘      └─┬─┘      
shuffle    shuffle    shuffle
   ↓          ↓          ↓
 bdac       adbc       cdba

RESULT: bdacadbccdba
Random rnd = new Random();
var s = "abcdabcdabcd";
var k = 3;
var n = 4;
var result = "";
for (int i = 0; i < k; i++)
{
    var current = s.Substring((i * n), n);
    var shuffled = string.Join("",current.OrderBy(x=>rnd.Next()));
    result += shuffled;
}

一个结果:

"bcadabcdbcda"

一个讨厌的 Linq 语句

给定

public static Random _rnd=new Random();

public static string WeirdShuffle(string input, int n) 
   => string.Concat(input.ToCharArray()
                         .Select((s, i) => (s, i))
                         .GroupBy(x => x.i / n)
                         .Select(g => string.Concat(g.Select(x => x.s)
                                                     .OrderBy(x => _rnd.Next()))));

用法

Console.WriteLine(WeirdShuffle("abcdabcdabcd",4));

其他资源

public string Shuffle(string str, int shuffleSize)
{
    if (str.Length % shuffleSize != 0)
    {
        throw new ArgumentException();
    }
    var result = Enumerable.Range(0, str.Length / shuffleSize)
        .Select(i =>
            SmallShuffle(str.Substring(i * shuffleSize, shuffleSize))
        );

    return string.Join("", result);
}

public string SmallShuffle(string str)
{
    char[] array = str.ToCharArray();
    Random rng = new Random();
    int n = array.Length;
    while (n > 1)
    {
        n--;
        int k = rng.Next(n + 1);
        var value = array[k];
        array[k] = array[n];
        array[n] = value;
    }
    return new string(array);
}

用法:

var s = "123456789123";
int k = 4;
var shuffled = Shuffle(s, k);

受这两个答案的影响很大:

像这样的东西应该有用。它本质上是经过修改的 Fisher-Yates 洗牌:

private static Random _random = new Random(); 

public static string ShuffleSubstrings(string input, int n, int k)
{
    if (input.Length != (n * k))
    {
        throw new ArgumentException("Length of input is not equal to kn");
    }

    var characters = input.ToCharArray();
    for (int g = 0; g < input.Length; g += n)
    {
        ShuffleSubarray(characters, g, n);
    }
    return new string(characters);
}

private static void ShuffleSubarray<T>(T[] array, int startPosition, int length)
{
    // For loop to handle individual group
    for (int i = startPosition; i < startPosition + length; ++i)
    {
        // shuffle taken from taken from https://www.dotnetperls.com/fisher-yates-shuffle, modified to work with groups)
        int r = i + _random.Next(length - (i % length));
        T tmp = array[r];
        array[r] = array[i];
        array[i] = tmp;
    }
}

Try it online

我喜欢这个:

private static Random _rnd = new Random();

public static string ShuffleSubstrings(string input, int n, int k)
{
    if (input.Length != (n * k))
    {
        throw new ArgumentException("Length of input is not equal to kn");
    }

    return String.Join("",
        from i in Enumerable.Range(0, k)
        from x in
            from y in input.Substring(i * n, n)
            orderby _rnd.Next()
            select y
        select x);
}
 static string Shffule(string str,int blockSize)
        {
            Random randomIndex= new Random();
            for (int indexInString = 0; indexInString < str.Length; indexInString+= blockSize)
            {
                for (int shufflesInBlock = 0; shufflesInBlock < blockSize; shufflesInBlock++)
                {
                    var firstRandomIndex = randomIndex.Next(indexInString, indexInString + blockSize);
                    var secondRandomIndex = randomIndex.Next(indexInString, indexInString + blockSize);
                    //str.Swap(firstRandomIndex, secondRandomIndex);
                }
            }
            return swapedString;
        }

这里有很多方法可以交换 2 个字符的字符串,所以我将把 string.Swap 扩展方法留给你

您可以通过更改 shufflesInBlock < blockSize 条件来控制嵌套循环中每个块的洗牌次数