How to get the array length of an expression parameter - c#

This method should return a function which can evaluate the scalar product of two vectors of the same size:
public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
var x = Expression.Parameter(typeof(T[]), "x");
var y = Expression.Parameter(typeof(T[]), "y");
var body = Enumerable
.Range(0, 3 /*Expression.ArrayLength(x)*/)
.Select(i => Expression.Multiply(
Expression.ArrayIndex(x, Expression.Constant(i)),
Expression.ArrayIndex(y, Expression.Constant(i))
))
.Aggregate(Expression.Add);
var lambda = Expression.Lambda<Func<T[], T[], T>>(body, x, y);
return lambda.Compile();
}
But in order to do that, I need to know the length of an array. There's a method Expression.ArrayLength() which returns UnaryExpression instead of the int and the expression cannot be cast explicitly to int. Is there a way of evaluating the array length as int beforehand?
UPD
Here's a unit test showing how this method should work:
[Test]
public void GetVectorMultiplyFunctionReturnsFunctionForInt()
{
var first = new int[] { 1, 2, 3 };
var second = new int[] { 2, 2, 2 };
var expected = 1 * 2 + 2 * 2 + 3 * 2;
var func = GetVectorMultiplyFunction<int>();
var actual = func(first, second);
Assert.AreEqual(expected, actual);
}

The length of an array is not part of the type definition, it's a value you can only obtain at runtime.
With the recent introduction of Generic Math, you can multiply and add values using generics without needing to build an expression tree;
public static T Calc<T>(T[] x, T[] y)
where T : struct, IMultiplyOperators<T,T,T>, IAdditionOperators<T,T,T>
{
T result = default(T);
for(var i = 0; i < x.Length && i < y.Length; i++)
result += x[i] * y[i];
return result;
}
But I assume that for your assignment you are expected to build an expression tree equivalent to the above method, then compile it.

This may not be what you want but seems to solve your problem if all you need to retain is the signature:
public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
return (T[] x, T[] y) => {
T result = default(T);
for(var i = 0; i < x.Length; i++)
{
var xd = (dynamic)x[i];
var yd = (dynamic)y[i];
result += (xd * yd);
}
return result;
};

The only parts of your code that require expression trees (assuming you can't use generic math or dynamics as per the other two solutions) are the operators (add and multiply).
If you compile the operator expressions separately, you can then use LINQ very easily, as per your original approach - something like this:
public static Func<T[], T[], T> GetVectorMultiplyFunction<T>() where T : struct
{
static Func<T,T,T> GetOperatorFunction(Func<Expression, Expression, BinaryExpression> operatorExpression)
{
var x = Expression.Parameter(typeof(T));
var y = Expression.Parameter(typeof(T));
var body = operatorExpression(x, y);
return Expression
.Lambda<Func<T, T, T>>(body, x, y)
.Compile();
}
var add = GetOperatorFunction(Expression.Add);
var multiply = GetOperatorFunction(Expression.Multiply);
return (xVector, yVector) =>
xVector
.Zip(yVector, multiply)
.Aggregate(add);
}

Related

Get lambda input in c#

I have never been really good at C# and I am trying to better myself by learing new things. I am now trying lambda's.
this is my code so far:
public static Func<float[], bool[]> CategoricalMap(Func<float, bool> mapper)
{
Func<float[], bool[]> fun = x => new bool[] { true };
return fun;
}
public static void Main()
{
Func<float, bool> success = x => x == 5.5f;
var result = CategoricalMap(success)(new float[] { 4f, 5.5f, 3.5f, -5.5f, 10.2f });
Console.ReadKey();
}
What I am trying to do is, to check what number is equal to 5.5f, but I don't know how to get the floats to show up in the CategoricalMap function. I know a bit of the puzzle, I have to do this:
mapper(float);
but I don't know how to get the floats from result to the function.
Please help.
Edit 1
I think I should make things more clear, A few weeks ago asked a someone to give me lambda challenges, sadly I have no way of contacting him. (kinda stupid of me)
this is what he gave me:
Create the lambda success which returns true if the given value is above or equal to 5.5f
Create the following function:
CategoricalMap
Creates a mapper function
Input: mapper a function of type Func<float, bool>
Output: a function of type Func<float[], bool[]> that takes in an array of booleans and applies the function mapper to each of the elements and stores the results in an integer array
Func<float[], bool[]> fun = x => new bool[] { true };
There x is your argument and it has type float[]. So in fact it is an array which you can iterate:
Func<float[], bool[]> fun = x => {
var result = new bool[x.Length];
for(int i = 0; i < x.Length; ++i) {
result[i] = mapper(x[i]);
}
return result;
};
Now you can use it as
public static Func<float[], bool[]> CategoricalMap(Func<float, bool> mapper)
{
Func<float[], bool[]> fun = x => {
var result = new bool[x.Length];
for(int i = 0; i < x.Length; ++i) {
result[i] = mapper(x[i]);
}
return result;
};
return fun;
}
public static void Main()
{
Func<float, bool> success = x => x == 5.5f;
var result = CategoricalMap(success)(new float[] { 4f, 5.5f, 3.5f, -5.5f, 10.2f });
Console.ReadKey();
}
But don't do that. This approach is terrible.

verify cummulative sum verify property efficiently with LINQ

I would like to verify if the sum of the elements (which are non-negativ) of my list isinferior to some values. And I don't want to calculate the the whole sum it is not necessary.(if we prove that the sum of the first element don't respect the property, we stop the computation)
So I would like a LINQ command that verify each element of the cummulative sum is inferior to some value as long as it see that the ineqality hold.
var b = a.Aggregate(new List<int> { 0 }, (ls, x) => { ls.Add(x + ls.Last()); return ls; }).All(x => x < 4);
This method doesn't work. All stop when it see that the ith element of the cummulative sum doesn't safisty the property but the whole cummulative sum is compute.
Have you a better way to do that? (I know we can do that efficiently with loop but I want to do that with LINQ)
if I use a loop:
var s = 0;
var b = true;
foreach(var x in list)
{
s=s+x;
if(s>4){ b= false; break;}
}
Thank you
You don't need to use a LINQ method to do what you want. You can write your own using enumerators and loops. After all, LINQ-to-Objects operations themselves are implemented using loops. For example TakeWhile is implemented as an iterator that loops over the source and yields matching elements :
static IEnumerable<TSource> TakeWhileIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate) {
int index = -1;
foreach (TSource element in source) {
checked { index++; }
if (!predicate(element, index)) break;
yield return element;
}
}
The downside is that this generates a state machine for the iterator and returns all matching elements, whether they are used or not.
You can write your own extension method that calculates the sum in a loop and returns true if the loop completes without reaching the limit :
public static bool SumBelow(this IEnumerable<int> source, int limit)
{
int sum=0;
foreach (var element in source)
{
sum+=element;
if (sum>limit)
{
return false;
}
}
return true;
}
And use it as an extension method :
var isSumBelow = someEnumerable.SumBelow(5);
Why not a generic method ?
There's no way to specify an operator constraint or an IAddable interface, which is why Sum() itself is implemented for each type separately, eg :
public static int Sum(this IEnumerable<int> source) {
if (source == null) throw Error.ArgumentNull("source");
int sum = 0;
checked {
foreach (int v in source) sum += v;
}
return sum;
}
The functional way
Passing the accumulator and condition checker as functions can be used to create one generic, reusable method that can work with any transormation and condition :
public static bool AccWithinLimit<T>(
this IEnumerable<T> source,
Func<T,T,T> accumulator,
Func<T,bool> terminator,
T seed=default)
{
T total=seed;
foreach (var element in source)
{
total = accumulator(element,total);
if (terminator(total))
{
return false;
}
}
return true;
}
This can be used to check for partial sums with integer arrays :
var myArray=new []{1,2,3};
var limit = 5;
var totalBelowLimit = myArray.AccWithinLimit(myArray,
(sum,elm)=>sum+elm,
sum=>sum>limit);
Or partial products with a list of doubles:
var myList = new List<double>{1.0, 2.0, 3.0};
var limit = 10;
var totalBelowLimit = myList.AccWithinLimit(myArray,
(sum,elm)=>sum*elm,
sum=>sum>limit,
1);
You can use TakeWhile to take items from the list until the sum exeeds some value
public void TestTakeWhileCumulativeSum()
{
int[] numbers = new[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int maxCumulativeSum = 5;
int previous = 0;
var result = numbers.TakeWhile(n => (previous = n + previous) <= maxCumulativeSum);
Assert.AreEqual(result.Count(), 5);
}

How to convert a multiple rank array using ConvertAll()?

I want to use ConvertAll like this:
var sou = new[,] { { true, false, false }, { true, true, true } };
var tar = Array.ConvertAll<bool, int>(sou, x => (x ? 1 : 0));
but I got compiler error:
cannot implicitly convert type bool[,] to bool[]
You could write a straightforward conversion extension:
public static class ArrayExtensions
{
public static TResult[,] ConvertAll<TSource, TResult>(this TSource[,] source, Func<TSource, TResult> projection)
{
if (source == null)
throw new ArgumentNullException("source");
if (projection == null)
throw new ArgumentNullException("projection");
var result = new TResult[source.GetLength(0), source.GetLength(1)];
for (int x = 0; x < source.GetLength(0); x++)
for (int y = 0; y < source.GetLength(1); y++)
result[x, y] = projection(source[x, y]);
return result;
}
}
Sample usage would look like this:
var tar = sou.ConvertAll(x => x ? 1 : 0);
The downside is that if you wanted to do any other transforms besides projection, you would be in a pickle.
Alternatively, if you want to be able to use LINQ operators on the sequence, you can do that easily with regular LINQ methods. However, you would still need a custom implementation to turn the sequence back into a 2D array:
public static T[,] To2DArray<T>(this IEnumerable<T> source, int rows, int columns)
{
if (source == null)
throw new ArgumentNullException("source");
if (rows < 0 || columns < 0)
throw new ArgumentException("rows and columns must be positive integers.");
var result = new T[rows, columns];
if (columns == 0 || rows == 0)
return result;
int column = 0, row = 0;
foreach (T element in source)
{
if (column >= columns)
{
column = 0;
if (++row >= rows)
throw new InvalidOperationException("Sequence elements do not fit the array.");
}
result[row, column++] = element;
}
return result;
}
This would allow a great deal more flexibility as you can operate on your source array as an IEnumerable{T} sequence.
Sample usage:
var tar = sou.Cast<bool>().Select(x => x ? 1 : 0).To2DArray(sou.GetLength(0), sou.GetLength(1));
Note that the initial cast is required to transform the sequence from IEnumerable paradigm to IEnumerable<T> paradigm since a multidimensional array does not implement the generic IEnumerable<T> interface. Most of the LINQ transforms only work on that.
If your array is of unknown rank, you can use this extension method (which depends on the MoreLinq Nuget package). I'm sure this can be optimized a lot, though, but this works for me.
using MoreLinq;
using System;
using System.Collections.Generic;
using System.Linq;
public static class ArrayExtensions
{
public static Array ConvertAll<TOutput>(this Array array, Converter<object, TOutput> converter)
{
foreach (int[] indices in GenerateIndices(array))
{
array.SetValue(converter.Invoke(array.GetValue(indices)), indices);
}
return array;
}
private static IEnumerable<int[]> GenerateCartesianProductOfUpperBounds(IEnumerable<int> upperBounds, IEnumerable<int[]> existingCartesianProduct)
{
if (!upperBounds.Any())
return existingCartesianProduct;
var slice = upperBounds.Slice(0, upperBounds.Count() - 1);
var rangeOfIndices = Enumerable.Range(0, upperBounds.Last() + 1);
IEnumerable<int[]> newCartesianProduct;
if (existingCartesianProduct.Any())
newCartesianProduct = rangeOfIndices.Cartesian(existingCartesianProduct, (i, p1) => new[] { i }.Concat(p1).ToArray()).ToArray();
else
newCartesianProduct = rangeOfIndices.Select(i => new int[] { i }).ToArray();
return GenerateCartesianProductOfUpperBounds(slice, newCartesianProduct);
}
private static IEnumerable<int[]> GenerateIndices(Array array)
{
var upperBounds = Enumerable.Range(0, array.Rank).Select(r => array.GetUpperBound(r));
return GenerateCartesianProductOfUpperBounds(upperBounds, Array.Empty<int[]>());
}
}

Aggregate values until a limit is reached

I need something similar to an AggregateWhile method. The standard System.Linq.Enumerable class doesn't provide it. Until now I've always been able to leverage the standard LINQ methods to solve every problem I've encountered. So I'd like to know if that's still possible in this case, or if I really do need to extend LINQ with a non-standard method.
The hypothetical AggregateWhile method would iterate over a sequence and apply the accumulator. The aggregation would be complete once a predicate returns false. The result is the aggregration of elements up to but not including the element for which the predicate failed.
Here's an example. We have a List { 1, 2, 3, 4, 5 } with an accumulator that adds the two input numbers together, and a predicate that states the accumulation must be less than 12. AggregateWhile would return 10 since that's the result of 1 + 2 + 3 + 4 and adding the final 5 would push the total over the limit. In code:
var list = new List<int> { 1, 2, 3, 4, 5 };
int total = list.AggregateWhile( (x, y) => x + y, a => a < 12 ); // returns 10
I need a purely functional solution, so closing over a temporary variable is not an option.
You could either write the function yourself, or carry a flag with your accumulator:
int total = list.Aggregate(new { value = 0, valid = true },
(acc, v) => acc.value + v < 12 && acc.valid ?
new { value = acc.value + v, valid = true } :
new { value = acc.value, valid = false },
acc => acc.value);
It's quite ugly, so writting a new AggregateWhile would be nicer:
public static TSource AggregateWhile<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func,
Func<TSource, bool> predicate)
{
using (IEnumerator<TSource> e = source.GetEnumerator()) {
TSource result = e.Current;
TSource tmp = default(TSource);
while (e.MoveNext() && predicate(tmp = func(result, e.Current)))
result = tmp;
return result;
}
}
(no error checking for brevity)
You can write your own extension method. This is not as perfect as the normal Linq methods, I cheated because I already know your requirements to make it simpler. In reality you may want an optional starting value for a and maybe different In and output types for T or other stuff:
public static class Linq
{
public static T AggregateWhile<T>(this IEnumerable<T> sequence, Func<T, T, T> aggregate, Func<T, bool> predicate)
{
T a;
foreach(var value in sequence)
{
T temp = aggregate(a, value);
if(!predicate(temp)) break;
a = temp;
}
return a;
}
}
Won't this work?
int total = list.Aggregate(0, (a, x) => (a + x) > 12 ? a : a + x);
Using Tuple<bool, int> as accumulator type, to break on first overflow:
int total = list.Aggregate(new Tuple<bool, int>(false, 0),
(a, x) => a.Item1 || (a.Item2 + x) > 12
? new Tuple<bool, int>(true, a.Item2)
: new Tuple<bool, int>(false, a.Item2 + x)
).Item2;
But it isn't so nice unfortunately.
Start using F#. ;)
let list = [ 1; 2; 3; 4; 5; 1 ]
let predicate = fun a -> a > 12
let total = list |> List.fold (fun (aval, astate) x ->
if astate || predicate (aval + x)
then (aval, true)
else (aval + x, false)) (0, false)
Tuple unpacking, no new bloat. And when you code it type inference makes it a breeze.
I asked this question a while back while encountering a problem that I later reframed into not needing AggregateWhile. But now I've encountered a slightly different problem which undoubtedly requires AggregateWhile or some direct substitute for it.
The solutions proposed by #sloth and #rkrahl are helpful. But they fall short in that the aggregation logic (addition in this case) is repeated twice. This doesn't seem like a big deal for the question's trivial example. But for my real problem, the calculation is complex so writing it twice is unacceptable.
Here's the solution I prefer (short of actual AggregateWhile methods):
class Program
{
static void Main( string[] args ) { new Program(); }
public Program()
{
var list = new int[] { 1, 2, 3, 4, 5 };
int total = list
.Aggregate( new Accumulator( 0 ), ( a, i ) => a.Next( i ), a => a.Total );
}
}
class Accumulator
{
public Accumulator( int total )
{
this.total = total;
}
public Accumulator Next( int i )
{
if ( isDone )
return this;
else {
int total = this.total + i;
if ( total < 12 )
return new Accumulator( total );
else {
isDone = true;
return this;
}
}
}
bool isDone;
public int Total
{
get { return total; }
}
readonly int total;
}
The ideal solution are fully implemented and tested AggregateWhile methods which correspond to the three Aggregate overloads. Short of that, the above pattern has the advantage that it can leverage the (somewhat lacking) functionality that's already present in the .NET framework.
Here is an AggregateWhile with a seed:
public static TAccumulate AggregateWhile<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, bool> predicate)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (func == null)
throw new ArgumentNullException(nameof(func));
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
var accumulate = seed;
foreach (var item in source)
{
var tmp = func(accumulate, item);
if (!predicate(tmp)) break;
accumulate = tmp;
}
return accumulate;
}

Pass lambda as argument

I have two methods where the only difference is one lambda predicate:
public static double LowerQuartile(this IOrderedEnumerable<double> list)
{
var median = list.Median();
var elements = list.Where(x => x < median).ToList();
if (!list.Contains(median))
elements.Add(median);
return elements.OrderBy(x => x).Median();
}
public static double UpperQuartile(this IOrderedEnumerable<double> list)
{
var median = list.Median();
var elements = list.Where(x => x > median).ToList();
if (!list.Contains(median))
elements.Add(median);
return elements.OrderBy(x => x).Median();
}
So I want to join them and pass a lambda as parameter. I tried with something like this:
public static double CalculateQuartile(IOrderedEnumerable<double> list, Expression<Func<IOrderedEnumerable<double>,bool>> predicate)
{
var median = list.Median();
var elements = list.Where(predicate).ToList();
if (!list.Contains(median))
elements.Add(median);
return elements.OrderBy(x => x).Median();
}
But it doesn't work. How could I do it?
It can be something like this
public static double Quartile(this IOrderedEnumerable<double> list,
Func<double,double,bool> predicate)
{
var median = list.Median();
var elements = list.Where(x=>predicate(x,median)).ToList();
if (!list.Contains(median))
elements.Add(median);
return elements.OrderBy(x => x).Median();
}
and you can use as
var val = list.Quartile((x, y) => x > y);
The lambdas x => x < median and x => x > median are both of the type Func<double, bool>. As you do have the median as another variable inside, you will have to accept that as a parameter too, so you would end up with Func<double, double, bool>:
public static double CalculateQuartile(this IOrderedEnumerable<double> list,
Func<double, double, bool> predicate)
{ … }
You could do it as an expression and paste in the reference to median at run-time, but I would suggest against it.
Instead, I would recommend you to solve this in a way, where the user of your function does not need to specify the correct lambda for it to work. After all, you just have two cases: upper quartile and lower quartile. So you might simply want to have a boolean flag as a parameter instead which allows you to choose between lower an upper quartile:
public static double CalculateQuartile(this IOrderedEnumerable<double> list,
bool calculateUpperQuartile = false)
{
var median = list.Median();
var predicate = calculateUpperQuartile ? (x => x > median) : (x => x < median);
var elements = list.Where(predicate).ToList();
if (!list.Contains(median))
elements.Add(median);
return elements.OrderBy(x => x).Median();
}
To make it more usable by the user, I would still offer both a CalculateUpperQuartile and CalculateLowerQuartile function though—but of course, you can internally use a single implementation to handle both.

Categories