以下代码根据1,2,3 = 3,2,1 = 2,3,1的逻辑返回所有不同的组合,因此它只返回该组数字的1个实例。
但是,我想更改该逻辑,以便返回所有数字集的所有实例。
我需要对下面的LINQ查询做什么" GetPowerSet"为了实现这一目标?
public void GetPowersets()
{
List<int> ints = new List<int>()
{
1,2,2,3,3
};
var results = GetPowerSet(ints);
List<String> combinations = new List<String>();
foreach (var result in results)
{
StringBuilder sb = new StringBuilder();
foreach (var intValue in result.OrderBy(x => x))
{
sb.Append(intValue + ",");
}
combinations.Add(sb.ToString());
}
string c1 = string.Join("|", combinations.ToArray()).Replace(",|", "|");
//c1 = "|1|2|1,2|2|1,2|2,2|1,2,2|3|1,3|2,3|1,2,3|2,3|1,2,3|2,2,3|1,2,2,3|3|1,3|2,3|1,2,3|2,3|1,2,3|2,2,3|1,2,2,3|3,3|1,3,3|2,3,3|1,2,3,3|2,3,3|1,2,3,3|2,2,3,3|1,2,2,3,3,"
}
public IEnumerable<IEnumerable<int>> GetPowerSet(List<int> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
这是我想要达到的最终结果:(没有重复的组合行:duplicate = 3,2,1和3,2,1是相同的东西。但是1,2,3和3,2, 1不是一回事,两者都应该在最终结果中)
1
2
3
1,2
1,3
2,1
2,3
2,2
3,1
3,2
3,3
1,2,3
1,2,2
1,3,2
1,3,3
2,1,3
2,1,2
2,3,1
2,3,2
2,3,3
2,2,1
2,2,3
3,1,2
3,1,3
3,2,1
3,2,2
3,2,3
3,3,1
3,3,2
1,2,3,2
1,2,3,3
1,2,2,3
1,3,2,2
1,3,2,3
1,3,3,2
2,1,3,2
2,1,3,3
2,1,2,3
2,3,1,2
2,3,1,3
2,3,2,1
2,3,2,3
2,3,3,1
2,3,3,2
2,2,1,3
2,2,3,1
2,2,3,3
3,1,2,2
3,1,2,3
3,1,3,2
3,2,1,2
3,2,1,3
3,2,2,1
3,2,2,3
3,2,3,1
3,2,3,2
3,3,1,2
3,3,2,1
3,3,2,2
1,2,3,2,3
1,2,3,3,2
1,2,2,3,3
1,3,2,2,3
1,3,2,3,2
1,3,3,2,2
2,1,3,2,3
2,1,3,3,2
2,1,2,3,3
2,3,1,2,3
2,3,1,3,2
2,3,2,1,3
2,3,2,3,1
2,3,3,1,2
2,3,3,2,1
2,2,1,3,3
2,2,3,1,3
2,2,3,3,1
3,1,2,2,3
3,1,2,3,2
3,1,3,2,2
3,2,1,2,3
3,2,1,3,2
3,2,2,1,3
3,2,2,3,1
3,2,3,1,2
3,2,3,2,1
3,3,1,2,2
3,3,2,1,2
3,3,2,2,1
&#34; foreach&#34;这样做的方式,往往导致内存异常&#34;一旦数字集太大(我预计LINQ不应该有这个问题)在下面。这是我想要的,返回我想要的结果集。但它很慢并且存在性能问题。我也欢迎提出如何改善它的建议。
public List<List<int>> GetAllCombinationsOfAllSizes(List<int> ints)
{
List<List<int>> returnResult = new List<List<int>>();
var distinctInts = ints.Distinct().ToList();
for (int j = 0; j < distinctInts.Count(); j++)
{
var number = distinctInts[j];
var newList = new List<int>();
newList.Add(number);
returnResult.Add(newList);
var listMinusOneObject = ints.Select(x => x).ToList();
listMinusOneObject.Remove(listMinusOneObject.Where(x => x == number).First());
if (listMinusOneObject.Count() > 0)
{
_GetAllCombinationsOfAllSizes(listMinusOneObject, newList, ref returnResult);
}
}
return returnResult;
}
public void _GetAllCombinationsOfAllSizes(List<int> ints, List<int> growingList, ref List<List<int>> returnResult)
{
var distinctInts = ints.Distinct().ToList();
for (int j = 0; j < distinctInts.Count(); j++)
{
var number = distinctInts[j];
var newList = growingList.ToList();
newList.Add(number);
returnResult.Add(newList);
var listMinusOneObject = ints.Select(x => x).ToList();
listMinusOneObject.Remove(listMinusOneObject.Where(x => x == number).First());
if (listMinusOneObject.Count() > 0)
{
_GetAllCombinationsOfAllSizes(listMinusOneObject, newList, ref returnResult);
}
}
}
我正在寻找的答案是:如何实现我想要的结果集,但是使用LINQ和C#来实现它,其方式比当前的#fore;&#34;更快更有效。我发布的方式?
答案 0 :(得分:2)
NEW UPDATE (删除旧代码,性能优于OP代码,产生输出)
static IEnumerable<int[]> EnumeratePermutations2(int[] ints)
{
Dictionary<int, int> intCounts = ints.GroupBy(n => n)
.ToDictionary(g => g.Key, g => g.Count());
int[] distincts = intCounts.Keys.ToArray();
foreach (int[] permutation in EnumeratePermutations2(new int[0], intCounts, distincts))
yield return permutation;
}
static IEnumerable<int[]> EnumeratePermutations2(int[] prefix, Dictionary<int, int> intCounts, int[] distincts)
{
foreach (int n in distincts)
{
int[] newPrefix = new int[prefix.Length + 1];
Array.Copy(prefix, newPrefix, prefix.Length);
newPrefix[prefix.Length] = n;
yield return newPrefix;
intCounts[n]--;
int[] newDistincts = intCounts[n] > 0
? distincts
: distincts.Where(x => x != n).ToArray();
foreach (int[] permutation in EnumeratePermutations2(newPrefix, intCounts, newDistincts))
yield return permutation;
intCounts[n]++;
}
}
答案 1 :(得分:0)
基于这个问题。
您的解决方案会返回所有结果集,包括重复项。您的解决方案不排除重复。您的示例输出确实排除了一些重复项,但列出了89组数据。
应该只有64个重复项,因为我理解组合的工作方式是2 ^ List.Count()= 2 ^ 6 = 64种组合
修订答案
我相信这很接近你想要的。我创建了一个简短的解决方案,但我认为它可以重新考虑并加快速度。以下链接有一些我认为应该使用的好的Set Classes:http://www.codeproject.com/Articles/23391/Set-Collections-for-C
我将使用的另一件事是 TPL库,它可以让您加快处理速度。链接:http://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
我的结果集产生了190套。使用以下代码,运行大约需要1.5分钟。
主程序
void Main()
{
var setList = new List<int>() {1,1,2,3,3,3};
var setSize = setList.Count();
var basePowerSet = PowerSet.Generate(setList);
var results = PowerSet.PS;
// Results generated in 1 Minute 23 seconds with no errors.
var sortedSets = new SortedSet<string>();
foreach( var item in results)
{
sortedSets.Add(item.ToString2());
}
foreach( var item in sortedSets)
{
Console.WriteLine(item);
}
}
PowerSet库
public static class PowerSet
{
// List with no Exact Duplicates but with Permutations
public static List<List<int>> PS = new List<List<int>>();
// This Method Generates the power set with No Exact Duplicates
// and stores the values into the Property PS.
public static List<List<int>> Generate(List<int> setList)
{
// Generate Base Data to use for final results
var setSize = setList.Count();
var basePowerSet = from m in Enumerable.Range(0, 1 << setSize)
select
from i in Enumerable.Range(0, setSize)
where (m & (1 << i)) != 0
select setList[i];
// Temporary Result Set with Duplicates
var results = new List<List<int>>();
// Step thru each set and generate list of Permutations for each
// Power Set generated above.
foreach( var item in basePowerSet )
{
var size = item.Count();
var positions = from m in Enumerable.Range(0, size)
select m;
var lItem = item.ToList();
// If the set has 2 or more elements in the set then generate Permutations
switch(size)
{
case 0:
case 1:
break;
default:
// Permutations generated from Linq Extension defined
// in Method Permute()
var posList = positions.Permute().ToList();
// remove first item which is a duplicate.
posList.RemoveAt(0);
// Generate new Lists based on all possiable
// combinations of the data in the set.
var x = new List<List<int>>();
foreach(var p in posList)
{
var y = new List<int>();
foreach(var v in p)
{
//v.Dump("xxxx");
y.Add(lItem[v]);
}
x.Add(y);
// Add New Permutation but
// Do not add a duplicate set.
AddNonDuplicate(x);
}
break;
}
// Add to Temp Results;
results.Add(item.ToList());
// Remove Duplicates
AddNonDuplicate(results);
}
return results;
}
// Custom Method used to compare values in a set to the
// Final Result Set named PS.
public static void AddNonDuplicate(List<List<int>> list )
{
//list.Dump();
if(list.Count() == 0)
return;
foreach(var item in list)
{
bool found = false;
var mySize = PS.Count();
if(mySize <= 0)
PS.Add(item);
else
foreach(var psItem in PS)
{
if( item.ToString2() == psItem.ToString2() )
found = true;
}
if(!found)
PS.Add(item);
}
}
}
扩展程序库
// My Extension Methods
public static class MyExt
{
public static IEnumerable<IEnumerable<T>> Permute<T>(this IEnumerable<T> list)
{
if (list.Count() == 1)
return new List<IEnumerable<T>> { list };
return list
.Select((a, i1) =>
Permute(list.Where((b, i2) => i2 != i1))
.Select(b => (new List<T> { a }).Union(b)))
.SelectMany(c => c);
}
public static string ToString2<T>(this List<T> list)
{
StringBuilder results = new StringBuilder("{ ");
var size = list.Count();
var pos = 1;
foreach( var i in list )
{
results.Append(i.ToString());
if(pos++!=size)
results.Append(", ");
}
results.Append(" }");
return results.ToString().Trim(',');
}
}
<强>结果
{ }
{ 1 }
{ 1, 1 }
{ 1, 1, 2 }
{ 1, 1, 2, 3 }
{ 1, 1, 2, 3, 3 }
{ 1, 1, 2, 3, 3, 3 }
{ 1, 1, 3 }
{ 1, 1, 3, 2 }
{ 1, 1, 3, 2, 3 }
{ 1, 1, 3, 2, 3, 3 }
{ 1, 1, 3, 3 }
{ 1, 1, 3, 3, 2 }
{ 1, 1, 3, 3, 2, 3 }
{ 1, 1, 3, 3, 3 }
{ 1, 1, 3, 3, 3, 2 }
{ 1, 2 }
{ 1, 2, 1 }
{ 1, 2, 1, 3 }
{ 1, 2, 1, 3, 3 }
{ 1, 2, 1, 3, 3, 3 }
{ 1, 2, 3 }
{ 1, 2, 3, 1 }
{ 1, 2, 3, 1, 3 }
{ 1, 2, 3, 1, 3, 3 }
{ 1, 2, 3, 3 }
{ 1, 2, 3, 3, 1 }
{ 1, 2, 3, 3, 1, 3 }
{ 1, 2, 3, 3, 3 }
{ 1, 2, 3, 3, 3, 1 }
{ 1, 3 }
{ 1, 3, 1 }
{ 1, 3, 1, 2 }
{ 1, 3, 1, 2, 3 }
{ 1, 3, 1, 2, 3, 3 }
{ 1, 3, 1, 3 }
{ 1, 3, 1, 3, 2 }
{ 1, 3, 1, 3, 2, 3 }
{ 1, 3, 1, 3, 3 }
{ 1, 3, 1, 3, 3, 2 }
{ 1, 3, 2 }
{ 1, 3, 2, 1 }
{ 1, 3, 2, 1, 3 }
{ 1, 3, 2, 1, 3, 3 }
{ 1, 3, 2, 3 }
{ 1, 3, 2, 3, 1 }
{ 1, 3, 2, 3, 1, 3 }
{ 1, 3, 2, 3, 3 }
{ 1, 3, 2, 3, 3, 1 }
{ 1, 3, 3 }
{ 1, 3, 3, 1 }
{ 1, 3, 3, 1, 2 }
{ 1, 3, 3, 1, 2, 3 }
{ 1, 3, 3, 1, 3 }
{ 1, 3, 3, 1, 3, 2 }
{ 1, 3, 3, 2 }
{ 1, 3, 3, 2, 1 }
{ 1, 3, 3, 2, 1, 3 }
{ 1, 3, 3, 2, 3 }
{ 1, 3, 3, 2, 3, 1 }
{ 1, 3, 3, 3 }
{ 1, 3, 3, 3, 1 }
{ 1, 3, 3, 3, 1, 2 }
{ 1, 3, 3, 3, 2 }
{ 1, 3, 3, 3, 2, 1 }
{ 2 }
{ 2, 1 }
{ 2, 1, 1 }
{ 2, 1, 1, 3 }
{ 2, 1, 1, 3, 3 }
{ 2, 1, 1, 3, 3, 3 }
{ 2, 1, 3 }
{ 2, 1, 3, 1 }
{ 2, 1, 3, 1, 3 }
{ 2, 1, 3, 1, 3, 3 }
{ 2, 1, 3, 3 }
{ 2, 1, 3, 3, 1 }
{ 2, 1, 3, 3, 1, 3 }
{ 2, 1, 3, 3, 3 }
{ 2, 1, 3, 3, 3, 1 }
{ 2, 3 }
{ 2, 3, 1 }
{ 2, 3, 1, 1 }
{ 2, 3, 1, 1, 3 }
{ 2, 3, 1, 1, 3, 3 }
{ 2, 3, 1, 3 }
{ 2, 3, 1, 3, 1 }
{ 2, 3, 1, 3, 1, 3 }
{ 2, 3, 1, 3, 3 }
{ 2, 3, 1, 3, 3, 1 }
{ 2, 3, 3 }
{ 2, 3, 3, 1 }
{ 2, 3, 3, 1, 1 }
{ 2, 3, 3, 1, 1, 3 }
{ 2, 3, 3, 1, 3 }
{ 2, 3, 3, 1, 3, 1 }
{ 2, 3, 3, 3 }
{ 2, 3, 3, 3, 1 }
{ 2, 3, 3, 3, 1, 1 }
{ 3 }
{ 3, 1 }
{ 3, 1, 1 }
{ 3, 1, 1, 2 }
{ 3, 1, 1, 2, 3 }
{ 3, 1, 1, 2, 3, 3 }
{ 3, 1, 1, 3 }
{ 3, 1, 1, 3, 2 }
{ 3, 1, 1, 3, 2, 3 }
{ 3, 1, 1, 3, 3 }
{ 3, 1, 1, 3, 3, 2 }
{ 3, 1, 2 }
{ 3, 1, 2, 1 }
{ 3, 1, 2, 1, 3 }
{ 3, 1, 2, 1, 3, 3 }
{ 3, 1, 2, 3 }
{ 3, 1, 2, 3, 1 }
{ 3, 1, 2, 3, 1, 3 }
{ 3, 1, 2, 3, 3 }
{ 3, 1, 2, 3, 3, 1 }
{ 3, 1, 3 }
{ 3, 1, 3, 1 }
{ 3, 1, 3, 1, 2 }
{ 3, 1, 3, 1, 2, 3 }
{ 3, 1, 3, 1, 3 }
{ 3, 1, 3, 1, 3, 2 }
{ 3, 1, 3, 2 }
{ 3, 1, 3, 2, 1 }
{ 3, 1, 3, 2, 1, 3 }
{ 3, 1, 3, 2, 3 }
{ 3, 1, 3, 2, 3, 1 }
{ 3, 1, 3, 3 }
{ 3, 1, 3, 3, 1 }
{ 3, 1, 3, 3, 1, 2 }
{ 3, 1, 3, 3, 2 }
{ 3, 1, 3, 3, 2, 1 }
{ 3, 2 }
{ 3, 2, 1 }
{ 3, 2, 1, 1 }
{ 3, 2, 1, 1, 3 }
{ 3, 2, 1, 1, 3, 3 }
{ 3, 2, 1, 3 }
{ 3, 2, 1, 3, 1 }
{ 3, 2, 1, 3, 1, 3 }
{ 3, 2, 1, 3, 3 }
{ 3, 2, 1, 3, 3, 1 }
{ 3, 2, 3 }
{ 3, 2, 3, 1 }
{ 3, 2, 3, 1, 1 }
{ 3, 2, 3, 1, 1, 3 }
{ 3, 2, 3, 1, 3 }
{ 3, 2, 3, 1, 3, 1 }
{ 3, 2, 3, 3 }
{ 3, 2, 3, 3, 1 }
{ 3, 2, 3, 3, 1, 1 }
{ 3, 3 }
{ 3, 3, 1 }
{ 3, 3, 1, 1 }
{ 3, 3, 1, 1, 2 }
{ 3, 3, 1, 1, 2, 3 }
{ 3, 3, 1, 1, 3 }
{ 3, 3, 1, 1, 3, 2 }
{ 3, 3, 1, 2 }
{ 3, 3, 1, 2, 1 }
{ 3, 3, 1, 2, 1, 3 }
{ 3, 3, 1, 2, 3 }
{ 3, 3, 1, 2, 3, 1 }
{ 3, 3, 1, 3 }
{ 3, 3, 1, 3, 1 }
{ 3, 3, 1, 3, 1, 2 }
{ 3, 3, 1, 3, 2 }
{ 3, 3, 1, 3, 2, 1 }
{ 3, 3, 2 }
{ 3, 3, 2, 1 }
{ 3, 3, 2, 1, 1 }
{ 3, 3, 2, 1, 1, 3 }
{ 3, 3, 2, 1, 3 }
{ 3, 3, 2, 1, 3, 1 }
{ 3, 3, 2, 3 }
{ 3, 3, 2, 3, 1 }
{ 3, 3, 2, 3, 1, 1 }
{ 3, 3, 3 }
{ 3, 3, 3, 1 }
{ 3, 3, 3, 1, 1 }
{ 3, 3, 3, 1, 1, 2 }
{ 3, 3, 3, 1, 2 }
{ 3, 3, 3, 1, 2, 1 }
{ 3, 3, 3, 2 }
{ 3, 3, 3, 2, 1 }
{ 3, 3, 3, 2, 1, 1 }
答案 2 :(得分:0)
我没有触及您的GetPowerSet
,而是创建了SetComparer
来过滤重复次数。
public class SetComparer : IEqualityComparer<IEnumerable<int>>
{
public bool Equals(IEnumerable<int> x, IEnumerable<int> y)
{
return Object.ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y));
}
public int GetHashCode(IEnumerable<int> set)
{
if (set == null) return 0;
//if you only want one of these 1,2,3 vs 3,2,1
//plug .OrderBy(x => x) before the Aggregate
return set.Aggregate(19, (s,i) => s * 31 + i);
}
}
只需将.Distinct(new SetComparer())
链接到结果或GetPowerSet
选择语句的末尾。