Just in time computation of combinations [duplicate] - c#

This question already has answers here:
System.OutOfMemoryException when generating permutations
(4 answers)
Closed 6 years ago.
I want to do something with every combination of ternaries for N variables:
example with 1:
T
F
U
example with 2:
TT
FT
UT
TF
FF
UF
UU
Is there a way to compute this but only as needed: For example:
var combinator = new Combinator<string>(2, {"T","F","U"});
List<String> tt = combinator.Next();
//tt contains {"T","T"}

You can implement it in an iterator method:
private IEnumerable<List<T>> Combinations<T>(int n, T[] values)
{
if (n == 0) yield return new List<T>();
else
{
foreach (var list in Combinations(n - 1, values))
foreach (var item in values)
{
var items = new List<T>(list);
items.Add(item);
yield return items;
}
}
}
This creates all combinations, but does it in a lazy way.
If you want you can create Combinator class like this:
class Combinator<T>
{
IEnumerator<List<T>> enumerator;
public Combinator(int n, T[] values)
{
enumerator = Combinations(n, values).GetEnumerator();
}
public List<T> Next()
{
return enumerator.MoveNext() ? enumerator.Current : null;
}
private IEnumerable<List<T>> Combinations<T>(int n, T[] values) { ... }
}

Probably not the most computationally efficient, but it's combinatorics, so the complexity is probably stuck being awful:
public static IEnumerable<List<T>> Combinations<T>( int count, IEnumerable<T> items )
{
if( count <= 0 ) yield break;
if( count == 1 )
{
foreach( var item in items ) yield return new List<T> { item };
yield break;
}
foreach( var item in items )
{
foreach( var combo in Combinations<T>( count - 1, items ) )
{
var result = new List<T> { item };
result.AddRange( combo );
yield return result;
}
}
}

It is not clear how you are getting your combinations of TFU.
You list only the following:
TT
FT
UT
TF
FF
UF
UU
However that is missing two combinations, and it should be like this (as far as I can work out):
TT
FT
UT
TF
FF
UF
TU
FU
UU
Assuming that the latter is actually the correct list, then you can compute it "on demand" like so:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
foreach (var combination in Combinator(new [] { "T", "F", "U" }, 2))
Console.WriteLine(string.Concat(combination));
}
public static IEnumerable<IEnumerable<T>> Combinator<T>(IEnumerable<T> sequence, int count)
{
if (count == 0)
{
yield return Enumerable.Empty<T>();
yield break;
}
foreach (T startingElement in sequence)
{
IEnumerable<T> remainingItems = sequence;
foreach (IEnumerable<T> permutationOfRemainder in Combinator(remainingItems, count - 1))
yield return permutationOfRemainder.Concat(new [] { startingElement});
}
}
}
}

You could achieve this by giving the cominations some ordering, so you can basically assign a mapping between them and the numbers from 1 to n^m (where n is the length of permutations and m is the number of strings). Then saving the state.
However what this does is bassically reimplementing IEnumerable. https://msdn.microsoft.com/de-de/library/system.collections.ienumerable(v=vs.110).aspx
Even simpler, if you need this in some sort of foreach loop, would be to use just a method that returns IEnumerable. IEnumerable will be lazily evaluated if you use the yield syntax.
http://www.dotnetperls.com/yield

Related

Don't take last record in linq C# [duplicate]

This question already has answers here:
How to take all but the last element in a sequence using LINQ?
(22 answers)
Drop the last item with LINQ [duplicate]
(3 answers)
Closed 3 years ago.
We all know that Skip() can omit records that are not needed at the start of a collection.
But is there a way to Skip() records at the end of a collection?
How do you not take the last record in a collection?
Or do you have to do it via Take()
ie, the below code,
var collection = MyCollection
var listCount = collection.Count();
var takeList = collection.Take(listCount - 1);
Is this the only way exclude the last record in a collection?
With enumerator you can efficiently delay yielding by one enumeration.
public static IEnumerable<T> WithoutLast<T>(this IEnumerable<T> source)
{
using (IEnumerator<T> e = source.GetEnumerator())
{
if (e.MoveNext() == false) yield break;
var current = e.Current;
while (e.MoveNext())
{
yield return current;
current = e.Current;
}
}
}
Usage
var items = new int[] {};
items.WithoutLast(); // returns empty
var items = new int[] { 1 };
items.WithoutLast(); // returns empty
var items = new int[] { 1, 2 };
items.WithoutLast(); // returns { 1 }
var items = new int[] { 1, 2, 3 };
items.WithoutLast(); // returns { 1, 2 }
A slightly different version of Henrik Hansen's answer:
static public IEnumerable<TSource> SkipLast<TSource>(
this IEnumerable<TSource> source, int count)
{
if (count < 0) count = 0;
var queue = new Queue<TSource>(count + 1);
foreach (TSource item in source)
{
queue.Enqueue(item);
if (queue.Count > count) yield return queue.Dequeue();
}
}
What about this:
static public IEnumerable<T> SkipLast<T>(this IEnumerable<T> data, int count)
{
if (data == null || count < 0) yield break;
Queue<T> queue = new Queue<T>(data.Take(count));
foreach (T item in data.Skip(count))
{
queue.Enqueue(item);
yield return queue.Dequeue();
}
}
Update
With help from some reviews an optimized version building on the same idea could be:
static public IEnumerable<T> SkipLast<T>(this IEnumerable<T> data, int count)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (count <= 0) return data;
if (data is ICollection<T> collection)
return collection.Take(collection.Count - count);
IEnumerable<T> Skipper()
{
using (var enumer = data.GetEnumerator())
{
T[] queue = new T[count];
int index = 0;
while (index < count && enumer.MoveNext())
queue[index++] = enumer.Current;
index = -1;
while (enumer.MoveNext())
{
index = (index + 1) % count;
yield return queue[index];
queue[index] = enumer.Current;
}
}
}
return Skipper();
}
One way would be:
var result = l.Reverse().Skip(1);
And if needed another Reverse to get them back in the original order.

How to select 2 items at a time?

I was writing a PascalCaseParser using Regex.Split and I came to the desire to select two items from an collection at a time.
This example code demonstrates.
void Main()
{
string pascalCasedString = "JustLikeYouAndMe";
var words = WordsFromPascalCasedString(pascalCasedString);
words.Dump();
}
IEnumerable<string> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
return rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c))
// how to select 2 elements at a time?
;
}
The result of above code is:
IEnumerable<String> (10 items)
J
ust
L
ike
Y
ou
A
nd
M
e
Every two elements of the collection make one result that I want the function WordsFromPascalCasedString to yield.
My questions is: How would you, in general, deal with a requirement to return two items at a time. I'm curious if there are any interesting non-brute-force approaches.
Personally, I'd go with Simon Belanger's answer in this particular case. But in general, to select consecutive pairs, from an IEnumerable, you'd use this:
IEnumerable<Tuple<string, string>> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
var array = rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c))
.ToArray();
var items = Enumerable.Range(0, array.Length / 2)
.Select(i => Tuple.Create(array[i * 2], array[i * 2 + 1]);
}
Or this, which takes more effort, but it's reusable and more efficient:
IEnumerable<Tuple<T, T>> Pairs<T>(IEnumerable<T> input)
{
var array = new T[2];
int i = 0;
foreach(var x in input)
{
array[i] = x;
i = (i + 1) % 2;
if (i == 0)
{
yield return Tuple.Create(array[0], array[1]);
}
}
}
IEnumerable<Tuple<string, string>> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
var output = rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c));
var items = Pairs(output);
}
It can easily be extended to groups of n:
IEnumerable<IEnumerable<T>> Batches<T>(IEnumerable<T> input, int n)
{
var array = new T[n];
int i = 0;
foreach(var x in input)
{
array[i] = x;
i = (i + 1) % n;
if (i == 0)
{
yield return array.ToArray();
}
}
if (i != 0)
{
yield return array.Take(i);
}
}
A similar method exists in MoreLINQ.
The regex should be ([A-Z][a-z]*). Adjust the last portion if you want to include numbers too. Use + instead of * if you want at least one lowercase element after the uppercase delimiter.
Edit As for the actual question, you will need to materialize and iterate in a for loop for better performance (passing the list once). In your specific problem, you can just use Regex.Matches
var result = Regex.Matches("([A-Z][a-z]*)([A-Z][a-z]*)?", "AbCdEfGhIj")
.OfType<Match>()
.Where(m => m.Success)
.Select(m => Tuple.Create(m.Groups[1].Value, m.Groups[2].Value));
This is just to share, I'm throwing the solution I came up with after getting inspired by the other answers. It is not better than the others...
void Main()
{
string pascalCasedString = "JustLikeYouAndMe";
var words = WordsFromPascalCasedString(pascalCasedString);
words.Dump();
}
IEnumerable<string> WordsFromPascalCasedString(string pascalCasedString)
{
var rx = new Regex("([A-Z])");
return rx.Split(pascalCasedString)
.Where(c => !string.IsNullOrEmpty(c))
.InPieces(2)
.Select(c => c.ElementAt(0) + c.ElementAt(1));
}
static class Ext
{
public static IEnumerable<IEnumerable<T>> InPieces<T>(this IEnumerable<T> seq, int len)
{
if(!seq.Any())
yield break;
yield return seq.Take(len);
foreach (var element in InPieces(seq.Skip(len), len))
yield return element;
}
}
Easiest is to write function that simply returns pairs.
Something like:
IEnumerable<Tuple<T,T>> Pairs<T>(IEnumerable<T> items)
{
T first = default(T);
bool hasFirst = false;
foreach(T item in items)
{
if (hasFirst)
yield return Tuple.Create(first, item);
else
first = item;
hasFirst = !hasFirst;
}
}
Aggregate is likely only one one-line approach. This is purely entertainment code due to amount of garbage created on a way, but there is no mutable objects used.
IEnumerable<Tuple<T,T>> Pairs<T>(IEnumerable<T> collection)
{
return collection
.Aggregate(
Tuple.Create(false, default(T), Enumerable.Empty<Tuple<T,T>>()),
(accumulate, item)=> !accumulate.Item1 ?
Tuple.Create(true, item, accumulate.Item3) :
Tuple.Create(false, default(T),
accumulate.Item3.Concat(
Enumerable.Repeat(Tuple.Create(accumulate.Item2, item), 1))),
accumulate => accumulate.Item3);
}
Zip of odd and even elements (index %2 ==/!= 0) is 2 line approach. Note that iterates source collection twice.
IEnumerable<Tuple<T,T>> Pairs<T>(IEnumerable<T> collection)
{
return collection
.Where((item, index)=>index %2 == 0)
.Zip(collection.Where((item, index)=>index %2 != 0),
(first,second)=> Tuple.Create(first,second));
}

Scrambling a string

How would one go about scrambling a string such as the following, so that every possible permutation is achieved? Is there a LINQ method for such an effort? I have searched Google, but could not find anything on it.
STRING = "Little Red Riding Hood"
This is an excellent permutation library I have used in the past. The article has a code snippet included that I believe would match your needs well (which I've slightly adapted):
var inputSet = myString.ToCharArray();
var P2 = new Permutations<char>(inputSet,
GenerateOption.WithRepetition);
string format2 = "Permutations of {{A A C}} with Repetition; size = {0}";
Console.WriteLine(String.Format(format2, P2.Count));
foreach(IList<char> p in P2) {
Console.WriteLine(String.Format("{{{0} {1} {2}}}", p[0], p[1], p[2]));
}
Here's a full sample program:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
internal class Program
{
private static void Main(string[] args)
{
var sentences = new List<string>
{
"Little Red Riding Hood",
"Three Little Pigs",
"Jack and the Beanstalk"
};
foreach (var sentence in sentences)
{
Console.WriteLine("----------------------------------");
foreach (var permutation in Permute(sentence.Split(' ')))
{
foreach (string word in permutation)
{
Console.Write(word + " ");
}
Console.WriteLine();
}
}
// If you want to put all the permutations for all the sentences into a List<string>, you can just do this:
List<string> permutations = new List<string>();
foreach (var sentence in sentences)
{
permutations.AddRange(Permute(sentence.Split(' ')).Select(perm => string.Join(" ", perm)));
}
Console.WriteLine("The total number of perms is: " + permutations.Count);
}
/// <summary>
/// Provides a sequence of enumerators for obtaining all permutations of a sequence.
/// Each enumeration in the returned sequence itself enumerates one of the permutations of the input sequence.
/// Use two nested foreach statements to visit each item in each permuted sequence.
/// </summary>
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> sequence)
{
return permute(sequence, sequence.Count());
}
// Returns an enumeration of enumerators, one for each permutation of the input.
private static IEnumerable<IEnumerable<T>> permute<T>(IEnumerable<T> sequence, int count)
{
if (count == 0)
{
yield return new T[0];
}
else
{
int startingElementIndex = 0;
foreach (T startingElement in sequence)
{
IEnumerable<T> remainingItems = allExcept(sequence, startingElementIndex);
foreach (IEnumerable<T> permutationOfRemainder in permute(remainingItems, count - 1))
{
yield return concat<T>(new T[] { startingElement }, permutationOfRemainder);
}
++startingElementIndex;
}
}
}
// Implements the recursive part of Permute<T>
private static void permute<T>(T[] items, int item, T[] permutation, bool[] used, Action<T[]> output)
{
for (int i = 0; i < items.Length; ++i)
{
if (!used[i])
{
used[i] = true;
permutation[item] = items[i];
if (item < (items.Length - 1))
{
permute(items, item + 1, permutation, used, output);
}
else
{
output(permutation);
}
used[i] = false;
}
}
}
// Enumerates over all items in the input, skipping over the item with the specified index.
private static IEnumerable<T> allExcept<T>(IEnumerable<T> input, int indexToSkip)
{
int index = 0;
foreach (T item in input)
{
if (index != indexToSkip)
{
yield return item;
}
++index;
}
}
// Enumerates over contents of two lists sequentially.
private static IEnumerable<T> concat<T>(IEnumerable<T> a, IEnumerable<T> b)
{
foreach (T item in a)
{
yield return item;
}
foreach (T item in b)
{
yield return item;
}
}
}
}
You want to do the Knuth/Fisher-Yates shuffle with the characters of the string.
Here are a bunch of C# implementations which you can adapt to a string instead of an array: Is using Random and OrderBy a good shuffle algorithm?
There are methods in the C++ Standard Template Library (STL), but I believe those are not accessible (in any maningful way) from C#. I believe you would have to write a little C++ wrapper for the STL and invoke that from C#; or code the permutations in C#.
Update:
Generating all permutations of N items is a necessary prelude to the Traveling Salesman Problem (TSP). Algorithms for this are all over the web, which will explain generating the permutaions in various possible sequential and parallel algorithms en passant.

How to take all but the last element in a sequence using LINQ?

Let's say I have a sequence.
IEnumerable<int> sequence = GetSequenceFromExpensiveSource();
// sequence now contains: 0,1,2,3,...,999999,1000000
Getting the sequence is not cheap and is dynamically generated, and I want to iterate through it once only.
I want to get 0 - 999999 (i.e. everything but the last element)
I recognize that I could do something like:
sequence.Take(sequence.Count() - 1);
but that results in two enumerations over the big sequence.
Is there a LINQ construct that lets me do:
sequence.TakeAllButTheLastElement();
The Enumerable.SkipLast(IEnumerable<TSource>, Int32) method was added in .NET Standard 2.1. It does exactly what you want.
IEnumerable<int> sequence = GetSequenceFromExpensiveSource();
var allExceptLast = sequence.SkipLast(1);
From https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.skiplast
Returns a new enumerable collection that contains the elements from source with the last count elements of the source collection omitted.
I don't know a Linq solution - But you can easily code the algorithm by yourself using generators (yield return).
public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
bool isFirst = true;
T item = default(T);
do {
hasRemainingItems = it.MoveNext();
if (hasRemainingItems) {
if (!isFirst) yield return item;
item = it.Current;
isFirst = false;
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 10);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.TakeAllButLast().Select(x => x.ToString()).ToArray()));
}
Or as a generalized solution discarding the last n items (using a queue like suggested in the comments):
public static IEnumerable<T> SkipLastN<T>(this IEnumerable<T> source, int n) {
var it = source.GetEnumerator();
bool hasRemainingItems = false;
var cache = new Queue<T>(n + 1);
do {
if (hasRemainingItems = it.MoveNext()) {
cache.Enqueue(it.Current);
if (cache.Count > n)
yield return cache.Dequeue();
}
} while (hasRemainingItems);
}
static void Main(string[] args) {
var Seq = Enumerable.Range(1, 4);
Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
Console.WriteLine(string.Join(", ", Seq.SkipLastN(3).Select(x => x.ToString()).ToArray()));
}
As an alternative to creating your own method and in a case the elements order is not important, the next will work:
var result = sequence.Reverse().Skip(1);
Because I'm not a fan of explicitly using an Enumerator, here's an alternative. Note that the wrapper methods are needed to let invalid arguments throw early, rather than deferring the checks until the sequence is actually enumerated.
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
return InternalDropLast(source);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source)
{
T buffer = default(T);
bool buffered = false;
foreach (T x in source)
{
if (buffered)
yield return buffer;
buffer = x;
buffered = true;
}
}
As per Eric Lippert's suggestion, it easily generalizes to n items:
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source, int n)
{
if (source == null)
throw new ArgumentNullException("source");
if (n < 0)
throw new ArgumentOutOfRangeException("n",
"Argument n should be non-negative.");
return InternalDropLast(source, n);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
{
Queue<T> buffer = new Queue<T>(n + 1);
foreach (T x in source)
{
buffer.Enqueue(x);
if (buffer.Count == n + 1)
yield return buffer.Dequeue();
}
}
Where I now buffer before yielding instead of after yielding, so that the n == 0 case does not need special handling.
With C# 8.0 you can use Ranges and indices for that.
var allButLast = sequence[..^1];
By default C# 8.0 requires .NET Core 3.0 or .NET Standard 2.1 (or above). Check this thread to use with older implementations.
Nothing in the BCL (or MoreLinq I believe), but you could create your own extension method.
public static IEnumerable<T> TakeAllButLast<T>(this IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
bool first = true;
T prev;
while(enumerator.MoveNext())
{
if (!first)
yield return prev;
first = false;
prev = enumerator.Current;
}
}
}
It would be helpful if .NET Framework was shipped with extension method like this.
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
{
var enumerator = source.GetEnumerator();
var queue = new Queue<T>(count + 1);
while (true)
{
if (!enumerator.MoveNext())
break;
queue.Enqueue(enumerator.Current);
if (queue.Count > count)
yield return queue.Dequeue();
}
}
if you don't have time to roll out your own extension, here's a quicker way:
var next = sequence.First();
sequence.Skip(1)
.Select(s =>
{
var selected = next;
next = s;
return selected;
});
A slight expansion on Joren's elegant solution:
public static IEnumerable<T> Shrink<T>(this IEnumerable<T> source, int left, int right)
{
int i = 0;
var buffer = new Queue<T>(right + 1);
foreach (T x in source)
{
if (i >= left) // Read past left many elements at the start
{
buffer.Enqueue(x);
if (buffer.Count > right) // Build a buffer to drop right many elements at the end
yield return buffer.Dequeue();
}
else i++;
}
}
public static IEnumerable<T> WithoutLast<T>(this IEnumerable<T> source, int n = 1)
{
return source.Shrink(0, n);
}
public static IEnumerable<T> WithoutFirst<T>(this IEnumerable<T> source, int n = 1)
{
return source.Shrink(n, 0);
}
Where shrink implements a simple count forward to drop the first left many elements and the same discarded buffer to drop the last right many elements.
If you can get the Count or Length of an enumerable, which in most cases you can, then just Take(n - 1)
Example with arrays
int[] arr = new int[] { 1, 2, 3, 4, 5 };
int[] sub = arr.Take(arr.Length - 1).ToArray();
Example with IEnumerable<T>
IEnumerable<int> enu = Enumerable.Range(1, 100);
IEnumerable<int> sub = enu.Take(enu.Count() - 1);
A slight variation on the accepted answer, which (for my tastes) is a bit simpler:
public static IEnumerable<T> AllButLast<T>(this IEnumerable<T> enumerable, int n = 1)
{
// for efficiency, handle degenerate n == 0 case separately
if (n == 0)
{
foreach (var item in enumerable)
yield return item;
yield break;
}
var queue = new Queue<T>(n);
foreach (var item in enumerable)
{
if (queue.Count == n)
yield return queue.Dequeue();
queue.Enqueue(item);
}
}
Why not just .ToList<type>() on the sequence, then call count and take like you did originally..but since it's been pulled into a list, it shouldnt do an expensive enumeration twice. Right?
The solution that I use for this problem is slightly more elaborate.
My util static class contains an extension method MarkEnd which converts the T-items in EndMarkedItem<T>-items. Each element is marked with an extra int, which is either 0; or (in case one is particularly interested in the last 3 items) -3, -2, or -1 for the last 3 items.
This could be useful on its own, e.g. when you want to create a list in a simple foreach-loop with commas after each element except the last 2, with the second-to-last item followed by a conjunction word (such as “and” or “or”), and the last element followed by a point.
For generating the entire list without the last n items, the extension method ButLast simply iterates over the EndMarkedItem<T>s while EndMark == 0.
If you don’t specify tailLength, only the last item is marked (in MarkEnd()) or dropped (in ButLast()).
Like the other solutions, this works by buffering.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Adhemar.Util.Linq {
public struct EndMarkedItem<T> {
public T Item { get; private set; }
public int EndMark { get; private set; }
public EndMarkedItem(T item, int endMark) : this() {
Item = item;
EndMark = endMark;
}
}
public static class TailEnumerables {
public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts) {
return ts.ButLast(1);
}
public static IEnumerable<T> ButLast<T>(this IEnumerable<T> ts, int tailLength) {
return ts.MarkEnd(tailLength).TakeWhile(te => te.EndMark == 0).Select(te => te.Item);
}
public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts) {
return ts.MarkEnd(1);
}
public static IEnumerable<EndMarkedItem<T>> MarkEnd<T>(this IEnumerable<T> ts, int tailLength) {
if (tailLength < 0) {
throw new ArgumentOutOfRangeException("tailLength");
}
else if (tailLength == 0) {
foreach (var t in ts) {
yield return new EndMarkedItem<T>(t, 0);
}
}
else {
var buffer = new T[tailLength];
var index = -buffer.Length;
foreach (var t in ts) {
if (index < 0) {
buffer[buffer.Length + index] = t;
index++;
}
else {
yield return new EndMarkedItem<T>(buffer[index], 0);
buffer[index] = t;
index++;
if (index == buffer.Length) {
index = 0;
}
}
}
if (index >= 0) {
for (var i = index; i < buffer.Length; i++) {
yield return new EndMarkedItem<T>(buffer[i], i - buffer.Length - index);
}
for (var j = 0; j < index; j++) {
yield return new EndMarkedItem<T>(buffer[j], j - index);
}
}
else {
for (var k = 0; k < buffer.Length + index; k++) {
yield return new EndMarkedItem<T>(buffer[k], k - buffer.Length - index);
}
}
}
}
}
}
public static IEnumerable<T> NoLast<T> (this IEnumerable<T> items) {
if (items != null) {
var e = items.GetEnumerator();
if (e.MoveNext ()) {
T head = e.Current;
while (e.MoveNext ()) {
yield return head; ;
head = e.Current;
}
}
}
}
I don't think it can get more succinct than this - also ensuring to Dispose the IEnumerator<T>:
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
using (var it = source.GetEnumerator())
{
if (it.MoveNext())
{
var item = it.Current;
while (it.MoveNext())
{
yield return item;
item = it.Current;
}
}
}
}
Edit: technically identical to this answer.
This is a general and IMHO elegant solution that will handle all cases correctly:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
IEnumerable<int> r = Enumerable.Range(1, 20);
foreach (int i in r.AllButLast(3))
Console.WriteLine(i);
Console.ReadKey();
}
}
public static class LinqExt
{
public static IEnumerable<T> AllButLast<T>(this IEnumerable<T> enumerable, int n = 1)
{
using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
{
Queue<T> queue = new Queue<T>(n);
for (int i = 0; i < n && enumerator.MoveNext(); i++)
queue.Enqueue(enumerator.Current);
while (enumerator.MoveNext())
{
queue.Enqueue(enumerator.Current);
yield return queue.Dequeue();
}
}
}
}
You could write:
var list = xyz.Select(x=>x.Id).ToList();
list.RemoveAt(list.Count - 1);
My traditional IEnumerable approach:
/// <summary>
/// Skips first element of an IEnumerable
/// </summary>
/// <typeparam name="U">Enumerable type</typeparam>
/// <param name="models">The enumerable</param>
/// <returns>IEnumerable of type skipping first element</returns>
private IEnumerable<U> SkipFirstEnumerable<U>(IEnumerable<U> models)
{
using (var e = models.GetEnumerator())
{
if (!e.MoveNext()) return;
for (;e.MoveNext();) yield return e.Current;
yield return e.Current;
}
}
/// <summary>
/// Skips last element of an IEnumerable
/// </summary>
/// <typeparam name="U">Enumerable type</typeparam>
/// <param name="models">The enumerable</param>
/// <returns>IEnumerable of type skipping last element</returns>
private IEnumerable<U> SkipLastEnumerable<U>(IEnumerable<U> models)
{
using (var e = models.GetEnumerator())
{
if (!e.MoveNext()) return;
yield return e.Current;
for (;e.MoveNext();) yield return e.Current;
}
}
Could be:
var allBuLast = sequence.TakeWhile(e => e != sequence.Last());
I guess it should be like de "Where" but preserving the order(?).
If speed is a requirement, this old school way should be the fastest, even though the code doesn't look as smooth as linq could make it.
int[] newSequence = int[sequence.Length - 1];
for (int x = 0; x < sequence.Length - 1; x++)
{
newSequence[x] = sequence[x];
}
This requires that the sequence is an array since it has a fixed length and indexed items.
A simple way would be to just convert to a queue and dequeue until only the number of items you want to skip is left.
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int n)
{
var queue = new Queue<T>(source);
while (queue.Count() > n)
{
yield return queue.Dequeue();
}
}
I would probably do something like this:
sequence.Where(x => x != sequence.LastOrDefault())
This is one iteration with a check that it isn't the last one for each time though.

Pair-wise iteration in C#, or sliding window enumerator

If I have an IEnumerable like:
string[] items = new string[] { "a", "b", "c", "d" };
I would like to loop thru all the pairs of consecutive items (sliding window of size 2). Which would be
("a", "b"), ("b", "c"), ("c", "d")
My solution was is this
public static IEnumerable<Pair<T, T>> Pairs(IEnumerable<T> enumerable) {
IEnumerator<T> e = enumerable.GetEnumerator(); e.MoveNext();
T current = e.Current;
while ( e.MoveNext() ) {
T next = e.Current;
yield return new Pair<T, T>(current, next);
current = next;
}
}
// used like this :
foreach (Pair<String,String> pair in IterTools<String>.Pairs(items)) {
System.Out.PrintLine("{0}, {1}", pair.First, pair.Second)
}
When I wrote this code, I wondered if there are already functions in the .NET framework that do the same thing and do it not just for pairs but for any size tuples.
IMHO there should be a nice way to do this kind of sliding window operations.
I use C# 2.0 and I can imagine that with C# 3.0 (using LINQ) there are more and nicer ways to do this, but I'm primarily interested in C# 2.0 solutions. Though, I will also appreciate C# 3.0 solutions.
In .NET 4 this becomes even easier:-
var input = new[] { "a", "b", "c", "d", "e", "f" };
var result = input.Zip(input.Skip(1), (a, b) => Tuple.Create(a, b));
Rather than require a tuple (pair) type, why not just accept a selector:
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
{
TSource previous = default(TSource);
using (var it = source.GetEnumerator())
{
if (it.MoveNext())
previous = it.Current;
while (it.MoveNext())
yield return resultSelector(previous, previous = it.Current);
}
}
Which allows you to skip the intermediate object if you want:
string[] items = new string[] { "a", "b", "c", "d" };
var pairs = items.Pairwise((x, y) => string.Format("{0},{1}", x, y));
foreach(var pair in pairs)
Console.WriteLine(pair);
Or you can use an anonymous type:
var pairs = items.Pairwise((x, y) => new { First = x, Second = y });
Update: I just implemented this on a real project and used C# 7.0 ValueTuple instead:
public static IEnumerable<(T, T)> Pairwise<T>(this IEnumerable<T> source)
{
var previous = default(T);
using (var it = source.GetEnumerator())
{
if (it.MoveNext())
previous = it.Current;
while (it.MoveNext())
yield return (previous, previous = it.Current);
}
}
The easiest way is to use ReactiveExtensions
using System.Reactive;
using System.Reactive.Linq;
and make yourself an extension method to kit bash this together
public static IEnumerable<IList<T>> Buffer<T>(this IEnumerable<T> seq, int bufferSize, int stepSize)
{
return seq.ToObservable().Buffer(bufferSize, stepSize).ToEnumerable();
}
Just for convenience, here is a selector-less version of #dahlbyk's answer.
public static IEnumerable<Tuple<T, T>> Pairwise<T>(this IEnumerable<T> enumerable)
{
var previous = default(T);
using (var e = enumerable.GetEnumerator())
{
if (e.MoveNext())
previous = e.Current;
while (e.MoveNext())
yield return Tuple.Create(previous, previous = e.Current);
}
}
A little late to the party, but as an alternative to all these extension methods, one might use an actual "sliding" Collection to hold (and discard) the data.
Here is one I ended up making today:
public class SlidingWindowCollection<T> : ICollection<T>
{
private int _windowSize;
private Queue<T> _source;
public SlidingWindowCollection(int windowSize)
{
_windowSize = windowSize;
_source = new Queue<T>(windowSize);
}
public void Add(T item)
{
if (_source.Count == _windowSize)
{
_source.Dequeue();
}
_source.Enqueue(item);
}
public void Clear()
{
_source.Clear();
}
...and just keep forwarding all other ICollection<T> methods to _source.
}
Usage:
int pairSize = 2;
var slider = new SlidingWindowCollection<string>(pairSize);
foreach(var item in items)
{
slider.Add(item);
Console.WriteLine(string.Join(", ", slider));
}
Here is my solution using a Stack. It is short and concise.
string[] items = new string[] { "a", "b", "c", "d" };
Stack<string> stack = new Stack<string>(items.Reverse());
while(stack.Count > 1)
{
Console.WriteLine("{0},{1}", stack.Pop(), stack.Peek());
}
You can take the same concept and use a queue which avoids the need for reversing the items and is even simpler:
var queue = new Queue<string>(items);
while (queue.Count > 1)
{
Console.WriteLine("{0},{1}", queue.Dequeue(), queue.Peek());
}
A short word about performance:
I believe it's important to realize that unless you know that a task is causing a bottleneck in your real application, it's probably not worth working out what the truly fastest way of doing is. Instead, write the code which does the job for you. Also, use code you can remember, so it easily flows out of your hand the next time you need it.
Nevertheless, in case you care for some performance data for 10.000.000 random strings:
Run #1
InputZip 00:00:00.7355567
PairwiseExtension 00:00:00.5290042
Stack 00:00:00.6451204
Queue 00:00:00.3245580
ForLoop 00:00:00.7808004
TupleExtension 00:00:03.9661995
Run #2
InputZip 00:00:00.7386347
PairwiseExtension 00:00:00.5369850
Stack 00:00:00.6910079
Queue 00:00:00.3246276
ForLoop 00:00:00.8272945
TupleExtension 00:00:03.9415258
Tested using Jon Skeet's micro benchmarking tool.
If you want to take a look at the source for the test go here: gist here
Something like this:
public static IEnumerable<TResult> Pairwise<T, TResult>(this IEnumerable<T> enumerable, Func<T, T, TResult> selector)
{
var previous = enumerable.First();
foreach (var item in enumerable.Skip(1))
{
yield return selector(previous, item);
previous = item;
}
}
Expanding on the previous answer to avoid of O(n2) approach by explicitly using the passed iterator:
public static IEnumerable<IEnumerable<T>> Tuples<T>(this IEnumerable<T> input, int groupCount) {
if (null == input) throw new ArgumentException("input");
if (groupCount < 1) throw new ArgumentException("groupCount");
var e = input.GetEnumerator();
bool done = false;
while (!done) {
var l = new List<T>();
for (var n = 0; n < groupCount; ++n) {
if (!e.MoveNext()) {
if (n != 0) {
yield return l;
}
yield break;
}
l.Add(e.Current);
}
yield return l;
}
}
For C# 2, before extension methods, drop the "this" from the input parameter and call as a static method.
Forgive me if I'm overlooking something, but why not something simple, like a for loop?:
public static List <int []> ListOfPairs (int [] items)
{
List <int> output = new List <int>();
for (int i=0; i < items.Length-1; i++)
{
Int [] pair = new int [2];
pair [0]=items [i];
pair [1]=items [i+1];
output.Add (pair);
}
return output;
}
C# 3.0 solution (sorry:)
public static IEnumerable<IEnumerable<T>> Tuples<T>(this IEnumerable<T> sequence, int nTuple)
{
if(nTuple <= 0) throw new ArgumentOutOfRangeException("nTuple");
for(int i = 0; i <= sequence.Count() - nTuple; i++)
yield return sequence.Skip(i).Take(nTuple);
}
This isn't the most performant in the world, but it's sure pleasant to look at.
Really, the only thing making this a C# 3.0 solution is the .Skip.Take construct, so if you just change that to adding the elements in that range to a list instead, it should be golden for 2.0. That said, it's still not performant.
Alternate Pairs implementation, using last pair to store previous value:
static IEnumerable<Pair<T, T>> Pairs( IEnumerable<T> collection ) {
Pair<T, T> pair = null;
foreach( T item in collection ) {
if( pair == null )
pair = Pair.Create( default( T ), item );
else
yield return pair = Pair.Create( pair.Second, item );
}
}
Simple Window implementation (only safe for private use, if caller does not save returned arrays; see note):
static IEnumerable<T[]> Window( IEnumerable<T> collection, int windowSize ) {
if( windowSize < 1 )
yield break;
int index = 0;
T[] window = new T[windowSize];
foreach( var item in collection ) {
bool initializing = index < windowSize;
// Shift initialized window to accomodate new item.
if( !initializing )
Array.Copy( window, 1, window, 0, windowSize - 1 );
// Add current item to window.
int itemIndex = initializing ? index : windowSize - 1;
window[itemIndex] = item;
index++;
bool initialized = index >= windowSize;
if( initialized )
//NOTE: For public API, should return array copy to prevent
// modifcation by user, or use a different type for the window.
yield return window;
}
}
Example use:
for( int i = 0; i <= items.Length; ++i ) {
Console.WriteLine( "Window size {0}:", i );
foreach( string[] window in IterTools<string>.Window( items, i ) )
Console.WriteLine( string.Join( ", ", window ) );
Console.WriteLine( );
}
The F# Seq module defines the pairwise function over IEnumerable<T>, but this function is not in the .NET framework.
If it were already in the .NET framework, instead of returning pairs it would probably accept a selector function due to the lack of support for tuples in languages like C# and VB.
var pairs = ns.Pairwise( (a, b) => new { First = a, Second = b };
I don't think any of the answers here really improve on your simple iterator implementation, which seemed the most natural to me (and the poster dahlbyk by the looks of things!) too.
I created a slightly modified version of the late-2020-updated code in #dahlbyk's answer. It is better suited for projects with nullable reference types enabled (<Nullable>enable</Nullable>). I also added basic docs.
/// <summary>
/// Enumerates over tuples of pairs of the elements from the original sequence. I.e. { 1, 2, 3 } becomes { (1, 2), (2, 3) }. Note that { 1 } becomes { }.
/// </summary>
public static IEnumerable<(T, T)> Pairwise<T>(this IEnumerable<T> source)
{
using var it = source.GetEnumerator();
if (!it.MoveNext())
yield break;
var previous = it.Current;
while (it.MoveNext())
yield return (previous, previous = it.Current);
}
This will make a single pass through the IEnumerable.
items.Aggregate(new List<string[]>(), (list, next) => { if (list.Count > 0) list[^1][1] = next; list.Add(new[] { next, next }); return list; }, (list) => { list.RemoveAt(list.Count -1); return list; });
New C# language allows to do something like this:
var pairlist = new (string, string)[] { ("a", "b"), ("b", "c"), ("c", "d") };
foreach (var pair in pairlist)
{
//do something with pair.Item1 & pair.Item2

Categories

Resources