Skip to content

Commit 1226163

Browse files
Improved combinations and added permutations.
Eliminated recusion.
1 parent f4c7582 commit 1226163

File tree

7 files changed

+381
-21
lines changed

7 files changed

+381
-21
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,6 @@ __pycache__/
270270
!.vscode/extensions.json
271271
.history
272272

273-
# End of https://www.gitignore.io/api/visualstudiocode
273+
# End of https://www.gitignore.io/api/visualstudiocode
274+
benchmarking/.vscode/launch.json
275+
benchmarking/.vscode/tasks.json

benchmarking/Combinations.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using BenchmarkDotNet.Attributes;
2+
using System.Linq;
3+
4+
namespace Open.Collections.Benchmarking
5+
{
6+
public class Combinations
7+
{
8+
public int Length { get; }
9+
public int Bounds { get; }
10+
11+
readonly int[] Source;
12+
readonly Collections.Combinations Combs = new();
13+
14+
public Combinations(int length = 6, int bounds = 7)
15+
{
16+
Length = length;
17+
Bounds = bounds;
18+
Source = Enumerable.Range(0, Bounds).ToArray();
19+
}
20+
21+
22+
[Benchmark]
23+
public int[][] AllPossible() => Source.Combinations(Length).Select(s=>s.ToArray()).ToArray();
24+
25+
[Benchmark]
26+
public int[][] Subsets() => Source.Subsets(Length).ToArray();
27+
28+
//[Benchmark]
29+
//public ImmutableArray<int>[] MemoizedStyle() => Combs.GetIndexes(Length).ToArray();
30+
}
31+
}

benchmarking/Open.Collections.Benchmarking.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp3.0</TargetFramework>
5+
<TargetFramework>net5.0</TargetFramework>
66
<RootNamespace>Open.Collections</RootNamespace>
77
</PropertyGroup>
88

@@ -16,6 +16,7 @@
1616
</PropertyGroup>
1717

1818
<ItemGroup>
19+
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
1920
<PackageReference Include="Open.Diagnostics" Version="1.4.1" />
2021
</ItemGroup>
2122

benchmarking/Program.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Open.Collections;
1+
using BenchmarkDotNet.Running;
2+
using Open.Collections;
23
using Open.Collections.Synchronized;
34
using Open.Diagnostics;
45
using System;
@@ -10,13 +11,32 @@ internal class Program
1011
{
1112
static void Main()
1213
{
13-
TestEntry.Test1();
14-
TestEntry.Test2();
15-
CollectionTests();
14+
Console.Clear();
15+
var perms = new char[] { 'A', 'B', 'C' }.Permutations(new char[3]);
16+
foreach(var p in perms)
17+
{
18+
Console.WriteLine(new string(p));
19+
}
20+
21+
//var combs = new Open.Collections.Benchmarking.Combinations();
22+
//OutputList(combs.AllPossible());
23+
//OutputList(combs.Subsets());
24+
25+
//BenchmarkRunner.Run<Open.Collections.Benchmarking.Combinations>();
26+
27+
//TestEntry.Test1();
28+
//TestEntry.Test2();
29+
//CollectionTests();
1630

1731
Console.Beep();
18-
Console.WriteLine("(press any key when finished)");
19-
Console.ReadKey();
32+
}
33+
34+
static void OutputList(int[][] list)
35+
{
36+
foreach (var e in list)
37+
Console.WriteLine(string.Join(' ', e));
38+
Console.WriteLine("Total: {0}", list.Length);
39+
Console.ReadLine();
2040
}
2141

2242
class TestEntry

source/Combinations.cs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using Open.Collections;
2+
using System;
3+
using System.Buffers;
4+
using System.Collections.Generic;
5+
using System.Collections.Immutable;
6+
using System.Linq;
7+
8+
namespace Open.Collections
9+
{
10+
public class Combinations
11+
{
12+
13+
/// <summary>
14+
/// Enumerate all possible m-size combinations of [0, 1, ..., bounds-1] array in lexicographic order (first [0, 1, 2, ..., length-1]).
15+
/// </summary>
16+
/// <param name="target"></param>
17+
/// <param name="length">The length of each result.</param>
18+
/// <param name="bounds">The maximum (excluded) value of the concecutive set of integers.</param>
19+
/// <returns>An enumerable that yields the target containing the next combination.</returns>
20+
public static IEnumerable<int[]> CopyTo(int[] target, int? length = null, int? bounds = null)
21+
{
22+
var len = length ?? target.Length;
23+
if (len > target.Length)
24+
throw new ArgumentOutOfRangeException(nameof(length), length, "Must be no more than the length of the buffer. ");
25+
var n = bounds ?? length;
26+
27+
var stack = new Stack<int>(len);
28+
stack.Push(0);
29+
30+
while (stack.Count > 0)
31+
{
32+
int index = stack.Count - 1;
33+
int value = stack.Pop();
34+
while (value < n)
35+
{
36+
target[index++] = value++;
37+
stack.Push(value);
38+
if (index != length) continue;
39+
yield return target;
40+
break;
41+
}
42+
}
43+
44+
}
45+
46+
47+
/// <summary>
48+
/// Enumerate all possible m-size combinations of [0, 1, ..., bounds-1] array in lexicographic order (first [0, 1, 2, ..., length-1]).
49+
/// </summary>
50+
/// <param name="length">The length of each result.</param>
51+
/// <param name="bounds">The maximum (excluded) value of the concecutive set of integers.</param>
52+
/// <returns>An enumerable that yields the buffer (could be any length equal to or greater than the length) containing the next combination.</returns>
53+
public static IEnumerable<int[]> GetPossibleIndexesBuffer(int length, int? bounds = null)
54+
{
55+
56+
var pool = ArrayPool<int>.Shared;
57+
var result = pool.Rent(length);
58+
try
59+
{
60+
return CopyTo(result, length, bounds);
61+
}
62+
finally
63+
{
64+
pool.Return(result);
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Enumerate all possible m-size combinations of [0, 1, ..., bounds-1] array in lexicographic order (first [0, 1, 2, ..., length-1]).
70+
/// </summary>
71+
/// <param name="length">The length of each result.</param>
72+
/// <param name="bounds">The maximum (excluded) value of the concecutive set of integers.</param>
73+
/// <returns>An enumerable that yields the buffer containing the next combination.</returns>
74+
public static IEnumerable<int[]> GetPossibleIndexes(int length, int? bounds = null)
75+
{
76+
foreach (var s in GetPossibleIndexesBuffer(length, bounds))
77+
{
78+
var a = new int[length];
79+
for (var i = 0; i < length; i++) a[i] = s[i];
80+
yield return a;
81+
}
82+
}
83+
84+
public Combinations()
85+
{
86+
Indexes = GetIndexes().Memoize();
87+
}
88+
89+
public IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> values)
90+
{
91+
var source = values is IReadOnlyList<T> v ? v : values.ToImmutableArray();
92+
return Indexes[source.Count].Select(c => source.Arrange(c));
93+
}
94+
95+
public IReadOnlyList<IReadOnlyList<T>> GetMemoizedCombinations<T>(IEnumerable<T> values)
96+
{
97+
var source = values is IReadOnlyList<T> v ? v : values.ToImmutableArray();
98+
return Indexes[source.Count].Select(c => source.Arrange(c).Memoize()).Memoize();
99+
}
100+
101+
IEnumerable<IReadOnlyList<ImmutableArray<int>>> GetIndexes()
102+
{
103+
yield return ImmutableArray<ImmutableArray<int>>.Empty;
104+
yield return ImmutableArray.Create(ImmutableArray.Create(0));
105+
yield return ImmutableArray.Create(ImmutableArray.Create(0, 1), ImmutableArray.Create(1, 0));
106+
107+
var i = 2;
108+
var indexes = new List<int> { 0, 1 };
109+
110+
loop:
111+
indexes.Add(i);
112+
++i;
113+
yield return GetIndexesCore(indexes).Memoize();
114+
goto loop;
115+
}
116+
117+
IEnumerable<ImmutableArray<int>> GetIndexesCore(IReadOnlyList<int> first)
118+
{
119+
var len = first.Count;
120+
var combinations = Indexes[len - 1];
121+
for (var i = 0; i < len; i++)
122+
{
123+
var builder = ImmutableArray.CreateBuilder<int>(len);
124+
foreach (var comb in combinations)
125+
{
126+
builder.Capacity = len;
127+
builder.Add(i);
128+
foreach (var c in comb)
129+
{
130+
var v = first[c < i ? c : (c + 1)];
131+
builder.Add(v);
132+
}
133+
yield return builder.MoveToImmutable();
134+
}
135+
}
136+
}
137+
138+
readonly LazyList<IReadOnlyList<ImmutableArray<int>>> Indexes;
139+
140+
public IReadOnlyList<ImmutableArray<int>> GetIndexes(int length) => Indexes[length];
141+
}
142+
}

0 commit comments

Comments
 (0)