C# 在具有大K的N个元素的列表中获取K个元素和更少元素的所有组合

C# 在具有大K的N个元素的列表中获取K个元素和更少元素的所有组合,c#,algorithm,permutation,C#,Algorithm,Permutation,我希望在列表中包含所有元素的组合,结果如下: 列表:{1,2,3} 1 2 3 1,2 1,3 2,3 我的问题是我有180个元素,我希望所有的组合最多有5个元素。我用4个元素进行测试,花了很长时间(2分钟),但都进行得很顺利。但对于5个元素,我得到了一个内存不足的异常 我目前的代码是: public IEnumerable<IEnumerable<Rondin>> getPossibilites(List<Rondin> rondins) { va

我希望在列表中包含所有元素的组合,结果如下:

列表:{1,2,3}

1
2
3
1,2
1,3
2,3
我的问题是我有180个元素,我希望所有的组合最多有5个元素。我用4个元素进行测试,花了很长时间(2分钟),但都进行得很顺利。但对于5个元素,我得到了一个内存不足的异常

我目前的代码是:

public IEnumerable<IEnumerable<Rondin>> getPossibilites(List<Rondin> rondins)
{
    var combin5 = rondins.Combinations(5);
    var combin4 = rondins.Combinations(4);
    var combin3 = rondins.Combinations(3);
    var combin2 = rondins.Combinations(2);
    var combin1 = rondins.Combinations(1);

    return combin5.Concat(combin4).Concat(combin3).Concat(combin2).Concat(combin1).ToList();
}
public IEnumerable getPossibilites(列表)
{
var combin5=rondins.组合(5);
var combin4=rondins.组合(4);
var combin3=rondins.组合(3);
var combin2=rondins.组合(2);
var combin1=rondins.组合(1);
返回combin5.Concat(combin4.Concat(combin3.Concat(combin2.Concat(combin1.ToList));
}
(摘自这个问题:)

公共静态IEnumerable组合(此IEnumerable元素,int k)
{
返回k==0?new[]{new T[0]}:
元素。选择多个((e,i)=>
元素.跳过(i+1).组合(k-1).选择(c=>(new[]{e}).Concat(c));
}
我需要在列表中搜索一个组合,其中每个元素加起来都接近一个值(具有一定的精度),这对于另一个列表中的每个元素都是如此。这部分有我的全部代码:

var possibilites = getPossibilites(opt.rondins);

possibilites = possibilites.Where(p => p.Sum(r => r.longueur + traitScie) < 144);

foreach(BilleOptimisee b in opt.billesOptimisees)
{
    var proches = possibilites.Where(p => p.Sum(r => (r.longueur + traitScie)) < b.chute && Math.Abs(b.chute - p.Sum(r => r.longueur)) - (p.Count() * 0.22) < 0.01).OrderByDescending(p => p.Sum(r => r.longueur)).ElementAt(0);

    if(proches != null)
    {
        foreach (Rondin r in proches)
        {
            opt.rondins.Remove(r);
            b.rondins.Add(r);
            possibilites = possibilites.Where(p => !p.Contains(r));
        }
    }
}
var possibilites=getPossibilites(opt.rondins);
可能性=可能性,其中(p=>p.Sum(r=>r.longueur+traitcie)<144);
foreach(可选账单优化视图中的账单优化对象b)
{
var proches=possibilites.Where(p=>p.Sum(r=>(r.longueur+traitScie))r.longueur))-(p.Count()*0.22)<0.01.OrderByDescending(p=>p.Sum(r=>r.longueur)).ElementAt(0);
if(进程!=null)
{
foreach(过程中的Rondin r)
{
选择rondins.移除(r);
b、 加上(r);
可能性=可能性,其中(p=>!p.Contains(r));
}
}
}
使用我的代码,我如何限制列表占用的内存?还是有更好的解决方案来搜索一组非常大的组合


如果我的问题不好,请告诉我原因,我会尽力学习,下次再问更好的问题;)

5个元素组合的输出列表将有大小为5的子列表~
1.5*10^9
(b为十亿)。如果您使用32位整数,即使忽略列表开销,并假设您有一个开销为0b的完美列表,也将是~200GB

您应该重新考虑,如果您真的需要像您那样生成列表,一些替代方案可能是:流式传输元素列表-即动态生成它们

这可以通过创建一个函数来实现,该函数获取最后一个组合作为参数,并输出下一个组合。(想一想是怎么做到的,想一想增加一个数字。你从最后一个到第一个,记住一个“结转”,直到你完成为止)

从4个流媒体中选择2个流媒体示例:

start: {4,3}
curr = start {4, 3}
curr = next(curr) {4, 2} // reduce last by one 
curr = next(curr) {4, 1} // reduce last by one
curr = next(curr) {3, 2} // cannot reduce more, reduce the first by one, and set the follower to maximal possible value
curr = next(curr) {3, 1} // reduce last by one
curr = next(curr) {2, 1} // similar to {3,2}
done.
现在,您需要考虑如何对大小为2的列表执行此操作,然后将其推广到任意大小,并对流式组合生成器进行编程


祝你好运

5个元素组合的输出列表将有大小为5的子列表~
1.5*10^9
(b为十亿)。如果您使用32位整数,即使忽略列表开销,并假设您有一个开销为0b的完美列表,也将是~200GB

您应该重新考虑,如果您真的需要像您那样生成列表,一些替代方案可能是:流式传输元素列表-即动态生成它们

这可以通过创建一个函数来实现,该函数获取最后一个组合作为参数,并输出下一个组合。(想一想是怎么做到的,想一想增加一个数字。你从最后一个到第一个,记住一个“结转”,直到你完成为止)

从4个流媒体中选择2个流媒体示例:

start: {4,3}
curr = start {4, 3}
curr = next(curr) {4, 2} // reduce last by one 
curr = next(curr) {4, 1} // reduce last by one
curr = next(curr) {3, 2} // cannot reduce more, reduce the first by one, and set the follower to maximal possible value
curr = next(curr) {3, 1} // reduce last by one
curr = next(curr) {2, 1} // similar to {3,2}
done.
现在,您需要考虑如何对大小为2的列表执行此操作,然后将其推广到任意大小,并对流式组合生成器进行编程


祝你好运

让您的精度在假想光谱中定义

使用实际索引访问叶,然后以所需的精度遍历叶

请参阅precisle@

虽然实现并非100%完整,但您可以在此处找到我使用的类似概念:

使用这个概念,我能够重新排序H.264接入单元及其底层网络接入层组件,我认为这是一个非常有趣的方式…除此之外,它还可以在使用相同内存量的情况下提高效率

等等,例如,0可以按0.1或0.01或0.001进行,这取决于列表中键的类型(双精度、浮点、向量等),如果处理器支持,则使用FPU或甚至可能是内部函数可能会带来额外的好处,因此,无论底层存储机制如何,排序和索引的速度都比普通集合快得多

使用这个概念可以进行非常有趣的排序。。。特别是如果您提供了一种过滤精度的机制


使用这种方法,我还能够在相当多的知名媒体库的位流解析器中找到几个bug…

让您的精度在虚拟频谱中定义

使用实际索引访问叶,然后以所需的精度遍历叶

请参阅precisle@

虽然实现并非100%完整,但您可以在此处找到我使用的类似概念:

使用这个概念,我能够重新排序H.264接入单元及其底层网络接入层组件,我认为这是一个非常有趣的方式…除此之外,它还可以在使用相同内存量的情况下提高效率

等,例如,0可以按0.1或0.01或0.001进行
public List<IEnumerable<Rondin>> getPossibilites(IEnumerable<Rondin> rondins, int nbElements, double minimum, double maximum, int instance = 0, double longueur = 0)
{
    if(instance == 0)
        timer = DateTime.Now;

    List<IEnumerable<Rondin>> liste = new List<IEnumerable<Rondin>>();

    //Get all distinct rondins that can fit into the maximal length
    foreach (Rondin r in rondins.Where(r => r.longueur < (maximum - longueur)).DistinctBy(r => r.longueur).OrderBy(r => r.longueur))
    {
        //Check the current length
        double longueur2 = longueur + r.longueur + traitScie;

        //If the current length is under the maximal length
        if (longueur2 < maximum)
        {
            //Get all the possibilities with all rondins except the current one, and add them to the list
            foreach (IEnumerable<Rondin> poss in getPossibilites(rondins.Where(rondin => rondin.id != r.id), nbElements - liste.Count, minimum, maximum, instance + 1, longueur2).Select(possibilite => possibilite.Concat(new Rondin[] { r })))
            {
                liste.Add(poss);
                if (liste.Count >= nbElements && nbElements > 0)
                    break;
            }

            //If this the current length in higher than the minimum, add it to the list
            if (longueur2 >= minimum)
                liste.Add(new Rondin[] { r });
        }

        //If we have enough possibilities, we stop the research
        if (liste.Count >= nbElements && nbElements > 0)
            break;

        //If the research is taking too long, stop the research and return the list;
        if (DateTime.Now.Subtract(timer).TotalSeconds > 30)
            break;
    }
    return liste;
}