C#置换给定n和最大数组长度的一组字符串

C#置换给定n和最大数组长度的一组字符串,c#,arrays,permutation,C#,Arrays,Permutation,如何根据设置的长度排列字符串集,我假设数组中有50个值,只想组合24个逗号分隔的值示例:(string1、string2、string3),但从不重复组合和顺序。我有下面的代码 class Program { static void Main(string[] args) { //var values1 = new[] { 1, 2, 3, 4, 5 }; //foreach (var permutation in values1.GetPerm

如何根据设置的长度排列字符串集,我假设数组中有50个值,只想组合24个逗号分隔的值示例:(string1、string2、string3),但从不重复组合和顺序。我有下面的代码

class Program
{
    static void Main(string[] args)
    {
        //var values1 = new[] { 1, 2, 3, 4, 5 };

        //foreach (var permutation in values1.GetPermutations())
        //{
        //    Console.WriteLine(string.Join(", ", permutation));
        //}

        var values2 = new[] { "asd", "das", "sad", "q1we", "asd" };

        foreach (var permutation in values2.GetPermutations())
        {
            Console.WriteLine(string.Join(",", permutation));
        }

        Console.ReadLine();
    }
}

public static class SomeExtensions
{
    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> enumerable)
    {
        var array = enumerable as T[] ?? enumerable.ToArray();

        var factorials = Enumerable.Range(0, array.Length + 1)
            .Select(Factorial)
            .ToArray();

        for (var i = 0L; i < factorials[array.Length]; i++)
        {
            var sequence = GenerateSequence(i, array.Length - 1, factorials);

            yield return GeneratePermutation(array, sequence);
        }
    }

    private static IEnumerable<T> GeneratePermutation<T>(T[] array, IReadOnlyList<int> sequence)
    {
        var clone = (T[])array.Clone();

        for (int i = 0; i < clone.Length - 1; i++)
        {
            Swap(ref clone[i], ref clone[i + sequence[i]]);
        }

        return clone;
    }

    private static int[] GenerateSequence(long number, int size, IReadOnlyList<long> factorials)
    {
        var sequence = new int[size];

        for (var j = 0; j < sequence.Length; j++)
        {
            var facto = factorials[sequence.Length - j];

            sequence[j] = (int)(number / facto);
            number = (int)(number % facto);
        }

        return sequence;
    }

    static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    private static long Factorial(int n)
    {
        long result = n;

        for (int i = 1; i < n; i++)
        {
            result = result * i;
        }

        return result;
    }
}
类程序
{
静态void Main(字符串[]参数)
{
//var值1=新[]{1,2,3,4,5};
//foreach(值1.GetPermutations()中的变量置换)
//{
//Console.WriteLine(string.Join(“,”,置换));
//}
var值2=新[]{“asd”、“das”、“sad”、“q1we”、“asd”};
foreach(值2中的变量置换。GetPermutations())
{
Console.WriteLine(string.Join(“,”,置换));
}
Console.ReadLine();
}
}
公共静态类扩展
{
公共静态IEnumerable GetPermutations(此IEnumerable可枚举)
{
变量数组=可枚举为T[]??可枚举.ToArray();
var阶乘=可枚举的.Range(0,数组.Length+1)
.选择(阶乘)
.ToArray();
对于(var i=0L;i

如何将字符串数组(24个值)组合成100行唯一组合?你能解释一下怎么做,最好的方法是什么吗

我想我会这样做

public static class StringPermutator
{
    /// <summary>
    /// Class to permutate input values
    /// </summary>
    /// <param name="inputValues">An array of inputs to be permutated</param>
    /// <param name="numberOfResults">The number of outputs we want to have</param>
    /// <param name="maxValuesPerRow">The number of values to be combined in each output row</param>
    /// <returns>An IEnumerable of unique permutated string ouptuts</returns>
    public static IEnumerable<string> Permutate<T>(T[] inputValues, int numberOfResults, int maxValuesPerRow)
    {
        HashSet<string> output = new HashSet<string>();
        Random rnd = new Random();

        //Loop until we have the number of results we want
        while (output.Count < numberOfResults)
        {
            StringBuilder sb = new StringBuilder();
            HashSet<int> usedIndexes = new HashSet<int>();

            //Loop until we have the right number of values in a single row
            while (usedIndexes.Count < maxValuesPerRow)
            {
                int index = rnd.Next(inputValues.Length);
                //Ensure that each index we use is unique and only used once per row
                if (usedIndexes.Add(index))
                    sb.Append(inputValues[index].ToString()).Append(",");
            }

            sb.Length--;    //remove the last comma
            output.Add(sb.ToString());   //value is only added if unique
        }

        return output.ToList();
    }
}
var result = StringPermutator.Permutate(stringValues, 100, 24);

foreach (var permutation in result)
{
    Console.WriteLine(string.Join(",", permutation));
}
基本上,该类使用HashSet,它确保只能输入唯一的值,因此我们可以确保输出不会重复,我们只需循环,直到生成正确数量的输出值

在这个循环中,我们随机选择一个要使用的索引,并确保每个输出值的索引也是唯一的,然后我们再次使用哈希集存储使用的索引并循环,直到我们将正确数量的值组合到一个输出行中

返回是一个可枚举列表。 这应该适用于任何类型的输入值,而不仅仅是字符串

编辑:

根据评论,我只是想澄清一下。
如果没有足够的输入来生成所需的排列数和行组合数,则可能陷入循环。因此,您应该编写一个方法来打破这种局面,但为了保持示例的简单性,我没有这样做。

我想我会这样做

public static class StringPermutator
{
    /// <summary>
    /// Class to permutate input values
    /// </summary>
    /// <param name="inputValues">An array of inputs to be permutated</param>
    /// <param name="numberOfResults">The number of outputs we want to have</param>
    /// <param name="maxValuesPerRow">The number of values to be combined in each output row</param>
    /// <returns>An IEnumerable of unique permutated string ouptuts</returns>
    public static IEnumerable<string> Permutate<T>(T[] inputValues, int numberOfResults, int maxValuesPerRow)
    {
        HashSet<string> output = new HashSet<string>();
        Random rnd = new Random();

        //Loop until we have the number of results we want
        while (output.Count < numberOfResults)
        {
            StringBuilder sb = new StringBuilder();
            HashSet<int> usedIndexes = new HashSet<int>();

            //Loop until we have the right number of values in a single row
            while (usedIndexes.Count < maxValuesPerRow)
            {
                int index = rnd.Next(inputValues.Length);
                //Ensure that each index we use is unique and only used once per row
                if (usedIndexes.Add(index))
                    sb.Append(inputValues[index].ToString()).Append(",");
            }

            sb.Length--;    //remove the last comma
            output.Add(sb.ToString());   //value is only added if unique
        }

        return output.ToList();
    }
}
var result = StringPermutator.Permutate(stringValues, 100, 24);

foreach (var permutation in result)
{
    Console.WriteLine(string.Join(",", permutation));
}
基本上,该类使用HashSet,它确保只能输入唯一的值,因此我们可以确保输出不会重复,我们只需循环,直到生成正确数量的输出值

在这个循环中,我们随机选择一个要使用的索引,并确保每个输出值的索引也是唯一的,然后我们再次使用哈希集存储使用的索引并循环,直到我们将正确数量的值组合到一个输出行中

返回是一个可枚举列表。 这应该适用于任何类型的输入值,而不仅仅是字符串

编辑:

根据评论,我只是想澄清一下。
如果没有足够的输入来生成所需的排列数和行组合数,则可能陷入循环。因此,您应该编写一个方法来打破这种局面,但为了保持示例的简单性,我没有这样做。

我建议使用更确定的置换生成器。将其与现有的LINQ扩展方法(如
Select()
Distinct()
Take()
)相结合,您就得到了所需的:

var results = values2.Permutations(24)
                     .Select(p => String.Join(",", p))
                     .Distinct()
                     .Take(100);
foreach (var permutation in results)
    Console.WriteLine(permutation);
其中,
Permutations()
作为扩展方法实现。这里的数字24表示每个排列中应该有多少项。它是nPk中的
k

Select()
调用创建一个包含特定排列的所有项的字符串

Distinct()
调用确保我们只得到唯一的字符串

Take()
调用限制了我们收集的字符串数量

下面是一个使用递归生成排列的简单实现:

public static IEnumerable<T[]> Permutations<T>(this IEnumerable<T> source, int k)
{
    if (k < 0)
        throw new ArgumentOutOfRangeException(nameof(k), "May not be negative");

    var items = source.ToArray();
    if (k > items.Length)
        throw new ArgumentOutOfRangeException(nameof(k), "May not be bigger than the number of items in source");

    var buffer = new ArraySegment<T>(items, 0, k);
    return Permute(0);

    IEnumerable<T[]> Permute(int depth)
    {
        if (depth == k)
        {
            yield return buffer.ToArray();
            yield break;
        }

        for (int i = depth; i < items.Length; i++)
        {
            Swap(depth, i);
            foreach (var permutation in Permute(depth + 1))
                yield return permutation;
            Swap(depth, i);
        }
    }

    void Swap(int a, int b)
    {
        if (a != b)
        {
            T t = items[a];
            items[a] = items[b];
            items[b] = t;
        }
    }
}
公共静态IEnumerable置换(此IEnumerable源代码,int k)
{
if(k<0)
抛出新的ArgumentOutOfRangeException(nameof(k),“可能不是负数”);
var items=source.ToArray();
if(k>items.Length)
抛出新ArgumentOutOfRangeException(nameof(k),“不能大于源中的项数”);
var buffer=新的ArraySegment(项,0,k);
返回排列(0);
IEnumerable置换(整数深度)
{
如果(深度==k)
{
产生返回缓冲区ToArray();
屈服断裂;
}
for(int i=深度;i