Single Object "Select" Method

Jan 14, 2010 at 1:06 AM
Edited Jan 14, 2010 at 1:08 AM

We've come across a use case where we compute two values via an aggregate and want to perform a calculation on those two values at the end of an operation.  Basically, we're creating a percent method.

We originally used two separate .Count() expressions on the same list, but it seemed that the two counts could get out of sync sometimes.  The following code demonstrates what we invented to do the counting in an "atomic" way.

 

list.Aggregate(new { MatchingItems = 0, TotalItems = 0 }, (total, item) =>
    item.MatchesSomeCriteria
        ? new { MatchingItems = total.MatchingItems + 1, TotalItems = total.TotalItems + 1}
        : new { total.MatchingItems, TotalItems = total.TotalItems + 1 }).??? -> the percentage of matching items

 

The problem now becomes computing the percent.  We couldn't think of any way to do this with built-in method, so we made a new method called "Transform".  Here's the definition.

 

    public static class ObjectExtensions
    {
        [ExpressionObserverMapping(typeof(Observable))]
        public static TResult Transform<T, TResult>(this T obj, Func<T, TResult> selector)
        {
            return selector(obj);
        }

        public static class Observable
        {
            public static IValueProvider<TResult> Transform<T, TResult>(T obj, Func<T, IValueProvider<TResult>> selector)
            {
                return selector(obj);
            }
        }
    }

To use it, we essentially replace the ??? with Transform(x => x.MatchingItems / x.TotalItems).  [math issues ignored for simplicity]

Having to make that method felt a little strange, but perhaps it is the best way to go.  If there's not a better way, hopefully this method will help somebody out in a similar situation.

 

 

 

Coordinator
Jan 15, 2010 at 7:12 AM

Since variables can't be used in lambda expressions I think this is a perfect solution to your problem and a great tip. Thanks.