简体   繁体   English

查找可以由数组中的数字总和以升序形成的数字

[英]find numbers that can be formed from sum of numbers from array in ascending order

I am trying to find the all possible values which are result of sum of values of given array. 我试图找到所有可能的值,这些值是给定数组的值之和的结果。 For example if given array is a = [50,100,120,260,360] then result will be [0,50,100,120,150,170,200,220,240,250,260,....] . 例如,如果给定数组为a = [50,100,120,260,360]则结果将为[0,50,100,120,150,170,200,220,240,250,260,....] How to implement it ? 如何执行呢?

I found one article realted to it but that is about to find the value which can't be formed using given array. 我发现有一篇关于它的文章,但是那是要找到不能使用给定数组形成的值。

Find smallest number which can't be formed by values of given array 查找不能由给定数组的值形成的最小数字

I found one more discussion related to something this but it is all about mathematics and I am still unable to understand how to implement it. 我发现又有一个与此相关的讨论,但都是关于数学的,我仍然无法理解如何实现它。 You can have a look at it Find all possible values which can be formed using some values 您可以看一下查找使用某些值可以形成的所有可能值

Any algorithm or any code in C# could help. C#中的任何算法或任何代码都可以提供帮助。

Edit 编辑

We can use a single value many times. 我们可以多次使用一个值。

more results could be 270 (50*1 + 100*1 + 120) , 300 (100*3), 310 (50 * 1 + 260 *1) etc. 更多结果可能是270(50 * 1 + 100 * 1 + 120),300(100 * 3),310(50 * 1 + 260 * 1)等。

This is what I use: 这是我用的:

Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
    (xs == null || !xs.Any())
        ? Enumerable.Empty<IEnumerable<int>>()
        : xs.Skip(1).Any()
            ? getAllSubsets(xs.Skip(1))
                .SelectMany(ys => new[] { ys, xs.Take(1).Concat(ys) })
            : new[] { Enumerable.Empty<int>(), xs.Take(1) };

Then you can do this: 然后,您可以执行以下操作:

var a = new [] { 50, 100, 120, 260, 360 };

Console.WriteLine(String.Join(", ", getAllSubsets(a).Select(x => x.Sum()).OrderBy(x => x)));

I get this: 我得到这个:

0, 50, 100, 120, 150, 170, 220, 260, 270, 310, 360, 360, 380, 410, 410, 430, 460, 480, 480, 510, 530, 530, 580, 620, 630, 670, 720, 740, 770, 790, 840, 890 0、50、100、120、150、170、220、260、270、310、360、360、380、410、410、430、460、480、480、510、530、530、580、620、630, 670、720、740、770、790、840、890

Knowing that values can be repeated then this is a way to go: 知道值可以重复,那么这是一种方法:

public IEnumerable<int> GenerateAllSums(int[] array)
{
    var buffer = new LinkedList<int>();
    buffer.AddFirst(0);
    while (true)
    {
        var first = buffer.First;
        var nexts = array.Select(a => first.Value + a);
        foreach (var next in nexts)
        {
            var x = buffer.First;
            while (x.Value < next)
            {
                x = x.Next;
                if (x == null)
                {
                    break;
                }
            }
            if (x == null)
            {
                buffer.AddLast(next);
            }
            else if (x.Value != next)
            {
                buffer.AddBefore(x, next);
            }
        }
        buffer.RemoveFirst();
        yield return first.Value;
    }
}

I can call it like so: 我可以这样称呼它:

var a = new [] { 50, 100, 120, 260, 360, };

Console.WriteLine(String.Join(", ", GenerateAllSums(a).Take(100)));

It's important to note that the .Take(...) is now vital as the sequence is infinite. 重要的是要注意,由于序列是无限的, .Take(...)现在至关重要。

Given the .Take(100) I get this result: 给定.Take(100)我得到以下结果:

0, 50, 100, 120, 150, 170, 200, 220, 240, 250, 260, 270, 290, 300, 310, 320, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, 850, 860, 870, 880, 890, 900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 1000, 1010, 1020, 1030, 1040, 1050, 1060, 1070, 1080, 1090, 1100, 1110, 1120, 1130, 1140, 1150, 1160, 1170 0、50、100、120、150、170、200、220、240、250、260、270、290、300、310、320、340、350、360、370、380、390、400、410、420, 430、440、450、460、470、480、490、500、510、520、530、540、550、560、570、580、590、600、610、620、630、640、650、660、670, 680,690,700,710,720,730,740,750,760,770,780,790,800,810,820,830,840,850,860,870,880,890,900,910,920, 930、940、950、960、970、980、990、1000、1010、1020、1030、1040、1050、1060、1070、1080、1090、1100、1110、1120、1130、1140、1150、1160、1170

Find all subset of your array using something like this then sum, you will get all the possible values if you don't need the duplicated one remove them. 使用类似的方法找到数组的所有子集,然后求和,如果不需要重复的值,则将其取下即可。

 int[] source = new int[] { 50,100,120,260,360 };
 for (int i = 0; i < Math.Pow(2, source.Length); i++)
 {
     int[] combination = new int[source.Length];
     for (int j = 0; j < source.Length; j++)
     {
         if ((i & (1 << (source.Length - j - 1))) != 0)
         {
             combination[j] = source[j];
         }
    }
    Console.WriteLine("[{0}, {1}, {2}]", combination[0], combination[1], combination[2]);
}
 var repeat = 8;
 int[] source = new int[] {
     50, 100, 120, 260, 360
 };
 List < int > results = new List < int > ();
 for (int i = 0; i < Math.Pow(repeat, source.Length); i++) {
     var sum = 0;
     var bin = Convert.ToString(i, repeat);
     for (var j = 0; j < bin.Length; j++) {
         var pos = int.Parse(bin[j].ToString());
         if (0 < pos) {
             sum += source[j] * pos;
         }
     }
     results.Add(sum);
 }
 Console.WriteLine(results.Union(source).Distinct().OrderBy(x = > x));

Here is the most efficient way to do that: 这是最有效的方法:

public static class Algorithms
{
    public static IEnumerable<int> AllSums(this int[] source)
    {
        var indices = new int[source.Length];
        for (int count = 0, sum = 0, next = 0; ; next++)
        {
            if (next < source.Length)
            {
                indices[count++] = next;
                sum += source[next];
                yield return sum;
            }
            else
            {
                if (count == 0) break;
                next = indices[--count];
                sum -= source[next];
            }
        }
    }
}

Sample usage: 用法示例:

var source = new[] { 50, 100, 120, 260, 360 };
Console.WriteLine("Source: {" + string.Join(", ", source.Select(n => n.ToString())) + "}");
Console.WriteLine("Sums: {" + string.Join(", ", source.AllSums().Select(n => n.ToString())) + "}");

or 要么

var source = new[] { 50, 100, 120, 260, 360 };
foreach (var sum in source.AllSums())
{
    // do something with the sum
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM