Table of contents generated with markdown-toc
LINQ-to-Object library to easily bifurcate LINQ data flows and join them back together.
You can split your collections data processing flow with Tee (T) and Wye (Y) easily.
It is inspired by the tee
linux command (but not the same thing!).
If you ever needed to build a fluent LINQ-to-object chain, but needed to process parts of data differently, this library call help you having a cleaner code.
PM > Install-Package LinqTee -Version 0.1.0-beta
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
//Split enumerable with some criteria
.Tee(LargerThan5)
//We choose to process both streams
.Process()
//Do something with the left side
.Left(even => even * 2)
//Do something else with the right side
.Right(odd => odd * 7)
//'wye' (join) them together.
.Wye() //<-- operate left-to-right
//In this case we concat the left with right side.
.Concatenate();
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
.Tee(LargerThan5)
.Process()
.Left(even => even * 2)
.Right(odd => odd * 7)
//Operate first on the right collection
.WyeRight() //<-- right-to-left
.Concatenate();
It works in a similar way of lodash
.
It weaves/intersperses two collections into one.
var odds = new []{1,3,5,7,9};
var evens = new []{2,4,6,8,10};
var values = zip(odds, evens);
//Values would be equal to
{1,2,3,4,5,6,7,8,9,10}
//We could also right zip them
var values2 = zipRight(odds, evens);
//It would be equal to
{2,1,4,3,6,5,8,7,10,9}
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
.Tee(LargerThan5)
.Process()
.Left(even => even * 2)
.Right(odd => odd * 7)
//Operate first on the right collection
.Wye() //<-- left-to-right
.Zip();
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
.Tee(LargerThan5)
.Process()
.Left(even => even * 2)
.Right(odd => odd * 7)
//Operate first on the right collection
.WyeRight() //<-- right-to-left
.Zip();
The API has been built to avoid misusing it.
Intellisense will be your best friend, but just in case:
IEnumerable<T>
.Tee(T => bool)
[
.Collect()
{ .Left(ref IList<T>) | .IgnoreLeft() }
{ .Right(ref IList<T>) | IgnoreRight() }
]
[
.Process()
{ .Left(T -> bool) | IgnoreLeft() }
{ .Right(T -> bool | IgnoreRight() }
{ .Wye() | .WyeRight() }
{ .Concatenate() | .Zip() | .OperateWith((IEnumerable<T>, IEnumerable<T>) => IEnumerable<T>) }
]
[
{ .Wye() | .WyeRight() }
{ .Concatenate() | .Zip() | .OperateWith((IEnumerable<T>, IEnumerable<T>) => IEnumerable<T>) }
]
;
By default the library includes concatenation
and zip
to merge a Tee
operation.
You can create any custom logic by implementing the IWyeableOperation<T>
interface.
You only have to implement how you want to merge two collections.
The interface has only a single method with two parameters which by convenience have been called left
and right
.
public interface IWyeableOperation<T>
{
IEnumerable<T> Operate(IEnumerable<T> left, IEnumerable<T> right);
}
You don't have to implement the opposite mapping. When using WyeRight()
method, your operation will just receive the left
and right
original collections swapped.
public class ConcatenateMyWay<T> : IWyeableOperation<T>
{
public IEnumerable<T> Operate(IEnumerable<T> left, IEnumerable<T> right)
{
return left.Concat(right);
}
}
Then you can use it as
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
.Tee(LargerThan5)
.Process()
.Left(even => even * 2)
.Right(odd => odd * 7)
.Wye()
.OperateWith(new ConcatenateMyWay()); //<-- generic way
We recommend creating your own extension method to have a cleaner code.
public static IEnumerable<T> ConcatenateMyWay<T>(this IWyeable<T> wyeable)
{
return wyeable.OperateWith(new Concatenate<T>());
}
Then you can invoke it as
bool LargerThan5(int x) => x > 5;
IEnumerable<int> values = Enumerable.Range(1, 10);
var processedValues = values
.Tee(LargerThan5)
.Process()
.Left(even => even * 2)
.Right(odd => odd * 7)
.Wye()
.ConcatenateMyWay(); // <-- much cleaner
Nothing prevents you from creating more complex nesting uses.
bool LargerThan5(int x) => x > 5;
var actual = Enumerable.Range(1, 10)
.Tee(x => x % 2 == 0)
.Process()
.Left(even =>
{
return even
.Tee(LargerThan5)
.Process()
.Left(evenLarger5 => evenLarger5)
.Right(evenSmaller5 => evenSmaller5)
.Wye()
.Concatenate();
})
.Right(odd =>
{
return odd
.Tee(LargerThan50)
.Process()
.Left(oddLarger5 => oddLarger5)
.Right(oddSmaller5 => oddSmaller5)
.Wye()
.Concatenate();
})
.Wye()
.Concatenate();
Starting range collection:
[1,2,3,4,5,6,7,8,9,10]
actual
variable result:
[6,8,10,2,4,7,9,1,3,5]