|
| 1 | +using System; |
| 2 | +using System.Collections.Concurrent; |
| 3 | +using System.Collections.Generic; |
| 4 | +using System.Collections.Immutable; |
| 5 | + |
| 6 | +namespace Open.Collections.Numeric |
| 7 | +{ |
| 8 | + public class PossibleAddends : IDisposable |
| 9 | + { |
| 10 | + public PossibleAddends() |
| 11 | + { |
| 12 | + } |
| 13 | + |
| 14 | + readonly ConcurrentDictionary<int, ConcurrentDictionary<int, IReadOnlyList<IReadOnlyList<int>>>> Cache = new(); |
| 15 | + |
| 16 | + public IReadOnlyList<IReadOnlyList<int>> UniqueAddendsFor(int sum, int count) |
| 17 | + => Cache |
| 18 | + .GetOrAdd(count, key => new ConcurrentDictionary<int, IReadOnlyList<IReadOnlyList<int>>>()) |
| 19 | + .GetOrAdd(sum, key => GetUniqueAddends(sum, count).Memoize()); |
| 20 | + |
| 21 | + public IEnumerable<IReadOnlyList<int>> GetUniqueAddends(int sum, int count) |
| 22 | + { |
| 23 | + if (count > int.MaxValue) |
| 24 | + throw new ArgumentOutOfRangeException(nameof(count), count, "Cannot be greater than signed 32 bit integer maximum."); |
| 25 | + if(count<2 || sum < 3) |
| 26 | + yield break; |
| 27 | + |
| 28 | + |
| 29 | + if (count==2) |
| 30 | + { |
| 31 | + int i = 0; |
| 32 | + loop2: |
| 33 | + i++; |
| 34 | + if (i * 2 >= sum) yield break; |
| 35 | + yield return ImmutableArray.Create(i, sum - i); |
| 36 | + |
| 37 | + goto loop2; |
| 38 | + } |
| 39 | + |
| 40 | + { |
| 41 | + int i = 2; |
| 42 | + var builder = ImmutableArray.CreateBuilder<int>(); |
| 43 | + |
| 44 | + while (++i < sum) |
| 45 | + { |
| 46 | + var next = sum - i; |
| 47 | + var addends = UniqueAddendsFor(i, count - 1); |
| 48 | + foreach (var a in addends) |
| 49 | + { |
| 50 | + builder.Capacity = count; |
| 51 | + if (a[a.Count - 1] >= next) continue; |
| 52 | + builder.AddRange(a); |
| 53 | + builder.Add(next); |
| 54 | + yield return builder.MoveToImmutable(); |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + public void Dispose() => Cache.Clear(); |
| 61 | + } |
| 62 | +} |
0 commit comments