C#置换给定n和最大数组长度的一组字符串
如何根据设置的长度排列字符串集,我假设数组中有50个值,只想组合24个逗号分隔的值示例:(string1、string2、string3),但从不重复组合和顺序。我有下面的代码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
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