有限长度的c#列表置换
我有一个报价列表,我想从中创建链长度有限的“链”(例如排列) 我已经用Kw组合学创建了排列。 但是,默认行为会在列表计数的长度中创建排列。我不知道如何将链条长度限制为“n” 以下是我当前的代码:有限长度的c#列表置换,c#,list,permutation,C#,List,Permutation,我有一个报价列表,我想从中创建链长度有限的“链”(例如排列) 我已经用Kw组合学创建了排列。 但是,默认行为会在列表计数的长度中创建排列。我不知道如何将链条长度限制为“n” 以下是我当前的代码: private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength) { List<List<Offers>> respon
private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength)
{
List<List<Offers>> response = new List<List<Offers>>();
foreach (var row in new Permutation(list.Count).GetRows())
{
List<Offers> innerList = new List<Offers>();
foreach (var mix in Permutation.Permute(row, list))
{
innerList.Add(mix);
}
response.Add(innerList);
innerList = new List<Offers>();
}
return response;
}
private static List GetPerms(List List,int chainLength)
{
列表响应=新列表();
foreach(新排列中的var行(list.Count).GetRows())
{
List innerList=新列表();
foreach(置换中的var混合。置换(行,列表))
{
innerList.Add(mix);
}
Add(innerList);
innerList=新列表();
}
返回响应;
}
执行人:
List<List<AdServer.Offers>> lst = GetPerms(offers, 2);
List lst=GetPerms(提供,2);
如果有人能提供更好的解决方案,我不会拘泥于组合数学。你不是在寻找置换,而是在寻找变异。这里有一个可能的算法。对于可能返回很多元素的函数,我更喜欢迭代器方法。这样,调用者就可以决定他是否真的需要所有元素:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
var variationElements = new HashSet<T>(); //for duplicate detection
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
var valid = true;
for (int i = 0; i < length; ++i)
{
var element = offers[startIndices[i]];
if (variationElements.Contains(element))
{
valid = false;
break;
}
variation.Add(element);
variationElements.Add(element);
}
if (valid)
yield return variation;
//Count up the indices
startIndices[length - 1]++;
for (int i = length - 1; i > 0; --i)
{
if (startIndices[i] >= offers.Count)
{
startIndices[i] = 0;
startIndices[i - 1]++;
}
else
break;
}
variationElements.Clear();
}
}
如果我没弄错,这就是你需要的 这将根据指定的链限制创建置换
public static List<List<T>> GetPerms<T>(List<T> list, int chainLimit)
{
if (list.Count() == 1)
return new List<List<T>> { list };
return list
.Select((outer, outerIndex) =>
GetPerms(list.Where((inner, innerIndex) => innerIndex != outerIndex).ToList(), chainLimit)
.Select(perms => (new List<T> { outer }).Union(perms).Take(chainLimit)))
.SelectMany<IEnumerable<IEnumerable<T>>, List<T>>(sub => sub.Select<IEnumerable<T>, List<T>>(s => s.ToList()))
.Distinct(new PermComparer<T>()).ToList();
}
class PermComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<T> obj)
{
return (int)obj.Average(o => o.GetHashCode());
}
}
publicstaticlist-GetPerms(List-List,int-chainLimit)
{
if(list.Count()==1)
返回新列表{List};
返回列表
.选择((外部,外部索引)=>
GetPerms(list.Where((内部,内部索引)=>innerIndex!=outerIndex.ToList(),chainLimit)
.Select(perms=>(新列表{outer}).Union(perms.Take(chainLimit)))
.SelectMany(sub=>sub.Select(s=>s.ToList())
.Distinct(新的PermComparer()).ToList();
}
类PermComparer:IEqualityComparer
{
公共布尔等于(列表x、列表y)
{
返回x.x(y);
}
public int GetHashCode(列表对象)
{
return(int)obj.Average(o=>o.GetHashCode());
}
}
你会这样称呼它
List<List<AdServer.Offers>> lst = GetPerms<AdServer.Offers>(offers, 2);
List lst=GetPerms(提供,2);
我使这个函数非常通用,因此您也可以将其用于其他用途
乙二醇
List List=新列表(新[]{“苹果”、“香蕉”、“橘子”、“樱桃”});
List perms=GetPerms(List,2);
结果
这里是另一个实现,我认为它应该比公认的答案更快(而且代码肯定更少) 使用编译器优化
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms
您能不能用
chainLength
替换列表。Count
呢?很抱歉回复太晚,但这正是我想要的,谢谢!
List<string> list = new List<string>(new[] { "apple", "banana", "orange", "cherry" });
List<List<string>> perms = GetPerms<string>(list, 2);
public static IEnumerable<IEnumerable<T>> GetVariationsWithoutDuplicates<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items.Distinct()
from permutation in GetVariationsWithoutDuplicates(items.Where(i => !EqualityComparer<T>.Default.Equals(i, item)).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<IEnumerable<T>> GetVariations<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items
from permutation in GetVariations(Remove(item, items).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<T> Prepend<T>(T first, IEnumerable<T> rest)
{
yield return first;
foreach (var item in rest) yield return item;
}
public static IEnumerable<T> Remove<T>(T item, IEnumerable<T> from)
{
var isRemoved = false;
foreach (var i in from)
{
if (!EqualityComparer<T>.Default.Equals(item, i) || isRemoved) yield return i;
else isRemoved = true;
}
}
public static void Test(Func<IList<int>, int, IEnumerable<IEnumerable<int>>> getVariations)
{
var max = 11;
var timer = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i < max; ++i)
for (int j = 1; j < i; ++j)
getVariations(MakeList(i), j).Count();
timer.Stop();
Console.WriteLine("{0,40}{1} ms", getVariations.Method.Name, timer.ElapsedMilliseconds);
}
// Make a list that repeats to guarantee we have duplicates
public static IList<int> MakeList(int size)
{
return Enumerable.Range(0, size/2).Concat(Enumerable.Range(0, size - size/2)).ToList();
}
GetVariations 11894 ms
GetVariationsWithoutDuplicates 9 ms
OtherAnswerGetVariations 22485 ms
OtherAnswerGetVariationsWithDuplicates 243415 ms
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms