重复获取 k 个元素的所有组合
Get all combinations of k elements with repetion
我想获得所有可能的重复组合列表。
例如
Input: 1,2,3
Result: 111,112,...,332,333
为此,我使用 this 修改后的方法,效果很好
public static IEnumerable<IEnumerable<T>> CombinationsWithRepeat<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } : elements.SelectMany((e, i) => elements.CombinationsWithRepeat(k - 1).Select(c => (new[] { e }).Concat(c)));
}
我的问题是这种递归方法的内存使用。输入 60 个元素且 K = 4 时,已经有一个 Out Of Memory Exception
。
我需要 运行 这个 K = 10。
问:有没有简单的方法可以避免这个异常?我需要迭代方法吗?
更新:
参考 Corak 的评论 -
K 必须是动态的
这应该适用于 60 个元素和 K = 10
但它不是动态的。
StreamWriter sr = new StreamWriter(@"c:\temp.dat");
List<char> cList = new List<char>() { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
for (int i = 0; i < cList.Count; i++)
for (int j = 0; j < cList.Count; j++)
for (int k = 0; k < cList.Count; k++)
sr.WriteLine(cList[i] + cList[j] + cList[k]);
给你:
const int SelectionSize = 4;
private static long _variationsCount = 0;
private static int[] _objects;
private static int[] _arr;
static void Main(string[] args)
{
_objects = new int[]{1,2,3,4,5,6,7,8,9,10};
_arr = new int[SelectionSize];
GenerateVariations(0);
Console.WriteLine("Total variations: {0}", _variationsCount);
}
static void GenerateVariations(int index)
{
if (index >= SelectionSize)
Print();
else
for (int i = 0; i < _objects.Length; i++)
{
_arr[index] = i;
GenerateVariations(index + 1);
}
}
private static void Print()
{
//foreach (int pos in arr)
//{
// Console.Write(objects[pos] + " ");
//}
//Console.WriteLine();
_variationsCount++;
}
即使选择大小为 10(大约需要 2 分钟),它也能正常工作。但请记住,控制台打印速度非常慢,这就是我将其注释掉的原因。如果你想打印列表,你可以使用 stringbuilder 并且只在程序完成时打印。
你的函数没有问题。如果您不尝试将生成的 IEnumerable 放入内存中(例如调用 ToArray()),您将不会出现内存不足异常。
下面的例子工作得很好。
class Program
{
static void Main(string[] args)
{
var input = Enumerable.Range(1, 60);
using (var textWriter = File.AppendText("result.txt"))
{
foreach (var combination in input.CombinationsWithRepeat(10))
{
foreach (var digit in combination)
{
textWriter.Write(digit);
}
textWriter.WriteLine();
}
}
}
}
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> CombinationsWithRepeat<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } : elements.SelectMany((e, i) => elements.CombinationsWithRepeat(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}
但是即使在硬盘上,您也没有足够的 space 来存储结果。有 60^10 种组合。每个组合使用 10-20 个字节。
您想如何使用函数的结果?
我想获得所有可能的重复组合列表。
例如
Input: 1,2,3
Result: 111,112,...,332,333
为此,我使用 this 修改后的方法,效果很好
public static IEnumerable<IEnumerable<T>> CombinationsWithRepeat<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } : elements.SelectMany((e, i) => elements.CombinationsWithRepeat(k - 1).Select(c => (new[] { e }).Concat(c)));
}
我的问题是这种递归方法的内存使用。输入 60 个元素且 K = 4 时,已经有一个 Out Of Memory Exception
。
我需要 运行 这个 K = 10。
问:有没有简单的方法可以避免这个异常?我需要迭代方法吗?
更新:
参考 Corak 的评论 - K 必须是动态的
这应该适用于 60 个元素和 K = 10
但它不是动态的。
StreamWriter sr = new StreamWriter(@"c:\temp.dat");
List<char> cList = new List<char>() { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
for (int i = 0; i < cList.Count; i++)
for (int j = 0; j < cList.Count; j++)
for (int k = 0; k < cList.Count; k++)
sr.WriteLine(cList[i] + cList[j] + cList[k]);
给你:
const int SelectionSize = 4;
private static long _variationsCount = 0;
private static int[] _objects;
private static int[] _arr;
static void Main(string[] args)
{
_objects = new int[]{1,2,3,4,5,6,7,8,9,10};
_arr = new int[SelectionSize];
GenerateVariations(0);
Console.WriteLine("Total variations: {0}", _variationsCount);
}
static void GenerateVariations(int index)
{
if (index >= SelectionSize)
Print();
else
for (int i = 0; i < _objects.Length; i++)
{
_arr[index] = i;
GenerateVariations(index + 1);
}
}
private static void Print()
{
//foreach (int pos in arr)
//{
// Console.Write(objects[pos] + " ");
//}
//Console.WriteLine();
_variationsCount++;
}
即使选择大小为 10(大约需要 2 分钟),它也能正常工作。但请记住,控制台打印速度非常慢,这就是我将其注释掉的原因。如果你想打印列表,你可以使用 stringbuilder 并且只在程序完成时打印。
你的函数没有问题。如果您不尝试将生成的 IEnumerable 放入内存中(例如调用 ToArray()),您将不会出现内存不足异常。
下面的例子工作得很好。
class Program
{
static void Main(string[] args)
{
var input = Enumerable.Range(1, 60);
using (var textWriter = File.AppendText("result.txt"))
{
foreach (var combination in input.CombinationsWithRepeat(10))
{
foreach (var digit in combination)
{
textWriter.Write(digit);
}
textWriter.WriteLine();
}
}
}
}
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> CombinationsWithRepeat<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } : elements.SelectMany((e, i) => elements.CombinationsWithRepeat(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}
但是即使在硬盘上,您也没有足够的 space 来存储结果。有 60^10 种组合。每个组合使用 10-20 个字节。
您想如何使用函数的结果?