diff --git a/MoreLinq.Test/CombinationsTest.cs b/MoreLinq.Test/CombinationsTest.cs
new file mode 100644
index 000000000..8645e9fbc
--- /dev/null
+++ b/MoreLinq.Test/CombinationsTest.cs
@@ -0,0 +1,147 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2019 Pierre Lando. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq.Test
+{
+ using NUnit.Framework;
+
+ ///
+ /// Tests of the Combinations() family of extension methods.
+ ///
+ [TestFixture]
+ public class CombinationsTest
+ {
+ ///
+ /// Verify that Combinations() behaves in a lazy manner.
+ ///
+ [Test]
+ public void TestCombinationsIsLazy()
+ {
+ new BreakingSequence().Combinations();
+ }
+
+ ///
+ /// Verify that the only Combinations of an empty sequence is the empty sequence.
+ ///
+ [Test]
+ public void TestEmptySequenceCombinations()
+ {
+ var sequence = Enumerable.Repeat(0, 0);
+ var result = sequence.Combinations();
+
+ Assert.That(result.Single(), Is.EqualTo(sequence));
+ }
+
+ ///
+ /// Verify that Combinations are returned in increasing size, starting with the empty set.
+ ///
+ [Test]
+ public void TestCombinationsInIncreasingOrder()
+ {
+ const int count = 5;
+ var sequence = Enumerable.Range(1, count);
+ var result = sequence.Combinations();
+
+ var prevCombinations = Enumerable.Empty();
+ foreach (var Combinations in result)
+ {
+ Assert.GreaterOrEqual(Combinations.Count, prevCombinations.Count());
+ prevCombinations = Combinations;
+ }
+ }
+
+ ///
+ /// Verify that the number of Combinations returned is correct, but don't verify the Combinations contents.
+ ///
+ [TestCase(0, ExpectedResult = 1)]
+ [TestCase(1, ExpectedResult = 2)]
+ [TestCase(2, ExpectedResult = 5)]
+ [TestCase(3, ExpectedResult = 16)]
+ [TestCase(4, ExpectedResult = 65)]
+ public int TestAllCombinationsExpectedCount(int sourceSize)
+ {
+ return Enumerable.Range(1, sourceSize).Combinations().Count();
+ }
+
+ private int[][][] Expected { get; } =
+ {
+ new[]
+ {
+ new int[] { }
+ },
+
+ new[]
+ {
+ new[] {1}, new[] {2}, new[] {3}, new[] {4}
+ },
+
+ new[]
+ {
+ new[] {1, 2}, new[] {1, 3}, new[] {1, 4},
+ new[] {2, 1}, new[] {2, 3}, new[] {2, 4},
+ new[] {3, 1}, new[] {3, 2}, new[] {3, 4},
+ new[] {4, 1}, new[] {4, 2}, new[] {4, 3}
+ },
+
+ new[]
+ {
+ new[] {1, 2, 3}, new[] {1, 2, 4}, new[] {1, 3, 2}, new[] {1, 3, 4}, new[] {1, 4, 2}, new[] {1, 4, 3},
+ new[] {2, 1, 3}, new[] {2, 1, 4}, new[] {2, 3, 1}, new[] {2, 3, 4}, new[] {2, 4, 1}, new[] {2, 4, 3},
+ new[] {3, 1, 2}, new[] {3, 1, 4}, new[] {3, 2, 1}, new[] {3, 2, 4}, new[] {3, 4, 1}, new[] {3, 4, 2},
+ new[] {4, 1, 2}, new[] {4, 1, 3}, new[] {4, 2, 1}, new[] {4, 2, 3}, new[] {4, 3, 1}, new[] {4, 3, 2}
+ },
+
+ new[]
+ {
+ new[] {1, 2, 3, 4}, new[] {1, 2, 4, 3}, new[] {1, 3, 2, 4}, new[] {1, 3, 4, 2}, new[] {1, 4, 2, 3}, new[] {1, 4, 3, 2},
+ new[] {2, 1, 3, 4}, new[] {2, 1, 4, 3}, new[] {2, 3, 1, 4}, new[] {2, 3, 4, 1}, new[] {2, 4, 1, 3}, new[] {2, 4, 3, 1},
+ new[] {3, 1, 2, 4}, new[] {3, 1, 4, 2}, new[] {3, 2, 1, 4}, new[] {3, 2, 4, 1}, new[] {3, 4, 1, 2}, new[] {3, 4, 2, 1},
+ new[] {4, 1, 2, 3}, new[] {4, 1, 3, 2}, new[] {4, 2, 1, 3}, new[] {4, 2, 3, 1}, new[] {4, 3, 1, 2}, new[] {4, 3, 2, 1}
+ }
+ };
+
+ ///
+ /// Verify that the complete Combinations results for a known set are correct.
+ ///
+ [Test]
+ public void TestAllCombinationsExpectedResults()
+ {
+ var sequence = Enumerable.Range(1, 4);
+ var actual = sequence.Combinations().ToList();
+ var expected = Expected.SelectMany(a => a);
+
+ CollectionAssert.AreEquivalent(expected, actual);
+ }
+
+ ///
+ /// Verify that the partial Combinations results for a known set are correct.
+ ///
+ [Test]
+ public void TestAllPartialCombinationsExpectedResults()
+ {
+ var sequence = Enumerable.Range(1, 4).ToList();
+
+ var i = 1;
+ foreach (var expected in Expected.Skip(1))
+ {
+ var actual = sequence.Combinations(i).ToList();
+ CollectionAssert.AreEquivalent(expected, actual);
+ i++;
+ }
+ }
+ }
+}
diff --git a/MoreLinq.Test/SubsetTest.cs b/MoreLinq.Test/SubsetTest.cs
index cc4725a2d..f02f4ef0d 100644
--- a/MoreLinq.Test/SubsetTest.cs
+++ b/MoreLinq.Test/SubsetTest.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+
namespace MoreLinq.Test
{
using System;
@@ -116,6 +118,19 @@ public void TestAllSubsetsExpectedResults()
Assert.That(subset, Is.EqualTo(expectedSubsets[index++]));
}
+ ///
+ /// See issue #645
+ ///
+ [Test]
+ public void Test0SubsetIsEmptyList()
+ {
+ var sequence = Enumerable.Range(1, 4);
+ var actual = sequence.Subsets(0);
+ var expected = new[] {new int[0]};
+
+ CollectionAssert.AreEquivalent(expected, actual);
+ }
+
///
/// Verify that the number of subsets for a given subset-size is correct.
///
diff --git a/MoreLinq/Combinations.cs b/MoreLinq/Combinations.cs
new file mode 100644
index 000000000..03e381206
--- /dev/null
+++ b/MoreLinq/Combinations.cs
@@ -0,0 +1,55 @@
+#region License and Terms
+// MoreLINQ - Extensions to LINQ to Objects
+// Copyright (c) 2019 Pierre Lando. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace MoreLinq
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ public static partial class MoreEnumerable
+ {
+ ///
+ /// Generate all the possible combination of the items from the input sequence.
+ ///
+ /// The type of the elements in the sequence
+ /// Sequence for which to produce combination
+ /// A sequence of all combination from the input sequence
+ /// Thrown if is
+ public static IEnumerable> Combinations(this IEnumerable sequence)
+ {
+ if (sequence == null) throw new ArgumentNullException(nameof(sequence));
+
+ return sequence.Subsets().SelectMany(Permutations);
+ }
+
+ ///
+ /// Generate all the possible combination of items from the input .
+ ///
+ /// The type of the elements in the sequence
+ /// Sequence for which to produce combination
+ /// The combinations size
+ /// A sequence of all combination from the input sequence
+ /// Thrown if is
+ public static IEnumerable> Combinations(this IEnumerable sequence, int size)
+ {
+ if (sequence == null) throw new ArgumentNullException(nameof(sequence));
+
+ return sequence.Subsets(size).SelectMany(Permutations);
+ }
+ }
+}
diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs
index 0b1211058..7c2d02efc 100644
--- a/MoreLinq/Extensions.g.cs
+++ b/MoreLinq/Extensions.g.cs
@@ -1061,6 +1061,34 @@ public static IEnumerable Choose(this IEnumerable source
}
+ /// Combinations extension.
+
+ [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
+ public static partial class CombinationsExtension
+ {
+ ///
+ /// Generate all the possible combination of the items from the input sequence.
+ ///
+ /// The type of the elements in the sequence
+ /// Sequence for which to produce combination
+ /// A sequence of all combination from the input sequence
+ /// Thrown if is
+ public static IEnumerable> Combinations(this IEnumerable sequence)
+ => MoreEnumerable.Combinations(sequence);
+
+ ///
+ /// Generate all the possible combination of items from the input .
+ ///
+ /// The type of the elements in the sequence
+ /// Sequence for which to produce combination
+ /// The combinations size
+ /// A sequence of all combination from the input sequence
+ /// Thrown if is
+ public static IEnumerable> Combinations(this IEnumerable sequence, int size)
+ => MoreEnumerable.Combinations(sequence, size);
+
+ }
+
/// CompareCount extension.
[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
diff --git a/MoreLinq/Subsets.cs b/MoreLinq/Subsets.cs
index 1491903bd..cd0ea2dda 100644
--- a/MoreLinq/Subsets.cs
+++ b/MoreLinq/Subsets.cs
@@ -108,7 +108,9 @@ public static IEnumerable> Subsets(this IEnumerable sequence, int
// preconditions. This however, needs to be carefully considered - and perhaps
// may change after further thought and review.
- return new SubsetGenerator(sequence, subsetSize);
+ return subsetSize == 0
+ ? (IEnumerable>) new[] {new List()}
+ : new SubsetGenerator(sequence, subsetSize);
}
///
diff --git a/README.md b/README.md
index d6923b81d..691f39e57 100644
--- a/README.md
+++ b/README.md
@@ -165,6 +165,13 @@ sequence of result elements for source elements where the function returns a
couple (2-tuple) having a `true` as its first element and result as the
second.
+### Combinations
+
+Returns a sequence of all of the combinations of any (or given) size that are
+part of the input sequence.
+
+This method has 2 overloads.
+
### CompareCount
Compares two sequences and returns an integer that indicates whether the