Pass lambda as argument - c#

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.

Related

How to get the array length of an expression parameter

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);
}

Select interval linq

Is there some way with LINQ to select certain numbers with shortcut criteria.
Like this:
I have numbers from 1 to 10000.
My criteria is (4012..4190|4229), meaning take numbers between 4012 to 4190 and number 4229:
static int[] test(string criteria)
{
// criteria is 4012..4190|4229
// select numbers from lab where criteria is met
int[] lab = Enumerable.Range(0, 10000).ToArray();
return lab;
}
This should be enough for your case:
return lab.Where((int1) => (int1 >= 4012 && int1 <= 4190) || int1 == 4229).ToArray();
Also a quick way of parsing your criteria would be to use RegEx:
Regex r = new Regex(#"\d+");
MatchCollection m = r.Matches(criteria);
int start = int.Parse(m[0].Value);
int end = int.Parse(m[1].Value);
int specific = int.Parse(m[2].Value);
return lab.Where((int1) => (int1 >= start && int1 <= end) || int1 == specific).ToArray();
If your criteria is always a string, you need some way to parse it, to Func<int, bool, but it's not LINQ specific. In the end you'll need something like this:
Func<int, bool> predicate = Parse(criteria);
return lab.Where(predicate).ToArray();
where very basic implementation of Parse might look as follows:
public static Func<int, bool> Parse(string criteria)
{
var alternatives = criteria
.Split('|')
.Select<string, Func<int, bool>>(
token =>
{
if (token.Contains(".."))
{
var between = token.Split(new[] {".."}, StringSplitOptions.RemoveEmptyEntries);
int lo = int.Parse(between[0]);
int hi = int.Parse(between[1]);
return x => lo <= x && x <= hi;
}
else
{
int exact = int.Parse(token);
return x => x == exact;
}
})
.ToArray();
return x => alternatives.Any(alt => alt(x));
}
You can concatenate two sequenses
int[] lab = Enumerable.Range(4012, 4190-4012).Concat(Enumerable.Range(4229,1)).ToArray();
Update:
you need to parse incoming criteria first
static int[] test(string criteria)
{
// criteria is 4012..4190|4229
// select numbers from lab where criteria is met
// assume you parsed your criteria to 2 dimentional array
// I used count for second part for convience
int[][] criteriaArray = { new int[]{ 4012, 50 }, new int[]{ 4229, 1 } };
var seq = Enumerable.Range(criteriaArray[0][0], criteriaArray[0][1]);
for (int i = 1; i < criteriaArray.Length; i++)
{
int start = criteriaArray[i][0];
int count = criteriaArray[i][1];
seq = seq.Concat(Enumerable.Range(start, count));
}
return seq.ToArray();
}
You could :
Flatten[{Range[4012, 4190], 4229}]
And in some way this would work as well 4012..4190|4229, but answer is exactly that - list of items from 4012 to 4190 and item 4229.
Lambda just imitates pure functions. However unless you have free wolfram kernel, using this approach might no be most cost effective. However, you do not need to write boilerplate code.

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;
}

using LINQ to find the cumulative sum of an array of numbers in C#

I have a csv string containing doubles (e.g "0.3,0.4,0.3"), and I want to be able to output a double array containing the cumulative sum of these numbers (e.g [0.3,0.7,1.0]).
So far, I have
double[] probabilities = textBox_f.Text.Split(new char[]{','}).Select(s => double.Parse(s)).ToArray();
which gives the numbers as an array, but not the cumulative sum of the numbers.
Is there any way to continue this expression to get what I want, or do I need to use iteration to create a new array from the array I already have?
There's a time for generality, and there's a time for solving the problem actually posed. This is one of the latter times. If you want to make a method that turns a sequence of doubles into a sequence of partial sums, then just do that:
public static IEnumerable<double> CumulativeSum(this IEnumerable<double> sequence)
{
double sum = 0;
foreach(var item in sequence)
{
sum += item;
yield return sum;
}
}
Easy. No messing around with aggregates and complicated queries and whatnot. Easy to understand, easy to debug, easy to use:
textBox_f.Text
.Split(new char[]{','})
.Select(s => double.Parse(s))
.CumulativeSum()
.ToArray();
Now, I note that if that is user input then double.Parse can throw an exception; it might be a better idea to do something like:
public static double? MyParseDouble(this string s)
{
double d;
if (double.TryParse(s, out d))
return d;
return null;
}
public static IEnumerable<double?> CumulativeSum(this IEnumerable<double?> sequence)
{
double? sum = 0;
foreach(var item in sequence)
{
sum += item;
yield return sum;
}
}
...
textBox_f.Text
.Split(new char[]{','})
.Select(s => s.MyParseDouble())
.CumulativeSum()
.ToArray();
and now you don't get an exception if the user makes a typing mistake; you get nulls.
I had a similar requirement some time ago. Basically, I needed to do an aggregation, but I also needed to select each intermediate value. So I wrote an extension method named SelectAggregate (probably not the most appropriate name, but I couldn't find anything better then) that can be used like that:
double[] numbers = new [] { 0.3, 0.4, 0.3 };
double[] cumulativeSums = numbers.SelectAggregate(0.0, (acc, x) => acc + x).ToArray();
Here's the code :
public static IEnumerable<TAccumulate> SelectAggregate<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
source.CheckArgumentNull("source");
func.CheckArgumentNull("func");
return source.SelectAggregateIterator(seed, func);
}
private static IEnumerable<TAccumulate> SelectAggregateIterator<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate previous = seed;
foreach (var item in source)
{
TAccumulate result = func(previous, item);
previous = result;
yield return result;
}
}
You want to use the Aggregate operator, with a List<double> as the aggregation accumulator. That way you can produce a projection which is itself a sequence of sums.
Here's an example to get you started:
double[] runningTotal = textBox_f.Text
.Split(new char[]{','})
.Select(s => double.Parse(s))
.Aggregate((IEnumerable<double>)new List<double>(),
(a,i) => a.Concat(new[]{a.LastOrDefault() + i}))
.ToArray();
var input=new double[]{ ... }
double sum=0;
var output=input
.Select(w=>sum+=w);
Why does it need to be LINQ?
var cumulative = new double[probabilities.Length];
for (int i = 0; i < probabilities.Length; i++)
cumulative[i] = probabilities[i] + (i == 0 ? 0 : cumulative[i-1]);
First of all i don't think that it is good task for Linq. Plain old foreach will do it better. But as a puzzle it is fine.
First idea was to use subqueries, but i don't like it, because it is O(n^2). Here is my linear solution:
double[] probabilities = new double[] { 0.3, 0.4, 0.3};
probabilities
.Aggregate(
new {sum=Enumerable.Empty<double>(), last = 0.0d},
(a, c) => new {
sum = a.sum.Concat(Enumerable.Repeat(a.last+c,1)),
last = a.last + c
},
a => a.sum
);
use RX :
var input=new double[]{ ... }
var output = new List<double>();
input.ToObservable().Scan((e, f) => f + e).Subscribe(output.Add);
This is actually pretty straightforward to generalize using generator. Here is a new extension method called Accumulate that works like a combination of Select and Aggregate. It returns a new sequence by applying a binary function to each element in the sequence and accumulated value so far.
public static class EnumerableHelpers
{
public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> self, U init, Func<U, T, U> f)
{
foreach (var x in self)
yield return init = f(init, x);
}
public static IEnumerable<T> Accumulate<T>(this IEnumerable<T> self, Func<T, T, T> f)
{
return self.Accumulate(default(T), f);
}
public static IEnumerable<double> PartialSums(this IEnumerable<double> self)
{
return self.Accumulate((x, y) => x + y);
}
public static IEnumerable<int> PartialSums(this IEnumerable<int> self)
{
return self.Accumulate((x, y) => x + y);
}
}
Here's my solution:
Linq
linear time
linear memory
no side effects
Only caveat is that it doesn't work for empty lists (trivial to handle).
var doublesSummed = doubles.Skip(1).Aggregate(
new {
sum = doubles.First(),
doubles = new [] {doubles.First()}.AsEnumerable()
},
(acc, nextDouble) => new {
sum = acc.sum + nextDouble,
doubles = acc.doubles.Append(acc.sum + nextDouble)
}
);
Demo
Here's a way of doing it using LINQ:
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
var doublesSummed = new List<double>();
Enumerable.Aggregate(doubles, (runningSum, nextFactor) => {
double currentSum = runningSum + nextFactor;
doublesSummed.Add(currentSum);
return currentSum;
});
doublesSummed.Dump();
In LINQPad:
4
5.9
10
12.9
Cumulative sum for List<double>:
var nums = new List<double>() { 0.3, 0.0, 0.4, 1.1 };
var cumsum = nums.Aggregate(new List<double> (),
(list, next) => { list.Add(list.LastOrDefault() + next); return list; });

Extension Method on IEnumerable

What is the solution for writing extension method dor IEumerable which resurns for example sum of squarea of elemetns
for example for:
IList<double> L = new List<double>();
L.Add(1);
L.Add(2);
L.Add(3);
var result = L.MyMethod();
expected value of result is 1*1 + 2*2 + 3*3 = 14
You don't need an extension method. You can just say
var sumOfSquares = list.Sum(x => x * x);
Obviously you can make it an extension method with
public static class EnumerableDoubleExtensions {
public static double SumSquares(this IEnumerable<double> source) {
Contract.Requires(source != null);
return source.Sum(x => x * x);
}
}
To do product you just say
list.Aggregate(1d, (p, x) => p * x);
which you can easily make an extension method via
public static class EnumerableDoubleExtensions {
public static double Product(this IEnumerable<double> source) {
Contract.Requires(source != null);
return source.Aggregate(1d, (p, x) => p * x);
}
}
Note that this uses Enumerable.Aggregate of which Enumerable.Sum is a special case.
The easiest way would be to use the overload of Enumerable.Sum that sums up a sequence of projected values from a sequence:
public static double GetSumOfSquares(this IEnumerable<double> numbers)
{
if(numbers == null)
throw new ArgumentNullException("numbers");
return numbers.Sum(x => x * x);
}
Do note that this will return 0D for an empty sequence. This is similar to:
numbers.Select(x => x * x)
.Sum();
As for your question about multiplying them, you could use Enumerable.Aggregate, which is a more general operator for performing accumulation-operations on sequences:
double product = numbers.Aggregate((productSoFar, next) => productSoFar * next);
This will throw an InvalidOperationException if the sequence is empty. If you would like to return something else in this case, use the overload that accepts an initial seed.

Categories