简体   繁体   中英

Compare List of Nullable Values

I have the following method to check if values1 crossed above values2 :

Boolean CrossAbove<T>(IList<T> values1, IList<T> values2) where T : IComparable {

  return values1[values1.Count - 2].CompareTo(values2[values2.Count - 2]) < 0 && values1.Last().CompareTo(values2.Last()) > 0;

}

So I might use something like:

List<Decimal> values1 = getValues1();
List<Decimal> values2 = getValues2();

Boolean result = CrossAbove(values1, values2);

But I need to pass nullable values. For example, using Decimal? in values1 :

List<Decimal?> values1 = getValues1();
List<Decimal> values2 = getValues2();

Boolean result = CrossAbove(values1, values2);

When comparing and one of the values is null then return false ...

How to change the CrossAbove method to allow this?

Update

I ended up with the following which allows to use one argument as nullable and another as not nullable. Or both nullables or not nullables:

Boolean CrossAbove<T>(IList<Nullable<T>> values1, IList<Nullable<T>> values2) where T : struct, IComparable {

  if (values1[values1.Count - 2] == null || values1.Last() == null || values2[values1.Count - 2] == null || values2.Last() == null)
    return false;

  return values1[values1.Count - 2].Value.CompareTo(values2[values2.Count - 2].Value) < 0 && values1.Last().Value.CompareTo(values2.Last().Value) > 0;

} 

Boolean CrossAbove<T>(IList<Nullable<T>> values1, IList<T> values2) where T : struct, IComparable => CrossAbove(values1, values2.Select(x => new Nullable<T>(x)).ToList());

Boolean CrossAbove<T>(IList<T> values1, IList<Nullable<T>> values2) where T : struct, IComparable => CrossAbove(values1.Select(x => new Nullable<T>(x)).ToList(), values2);

Boolean CrossAbove<T>(IList<T> values1, IList<T> values2) where T : struct, IComparable => CrossAbove(values1.Select(x => new Nullable<T>(x)).ToList(), values2.Select(x => new Nullable<T>(x)).ToList());

I couldn't find a better way to do this and satisfy the requirements.

Any though?

You can modify your method to receive the comparison logic, something like:

bool CrossAbove<T>(IList<T> values1, IList<T> values2, Func<T, T, int> compare)
{
     return compare(values1[values1.Count - 2], values2[values2.Count - 2]) < 0 && compare(values1.Last(), values2.Last()) > 0;
}

Then, for your first example it would be:

CrossAbove(values1, values2, decimal.Compare);

For your List<decimal?> example call you can invoke your method with a compare like the following:

CrossAbove(values1, values2, (v1, v2) => {
    if (v1.HasValue && v2.HasValue) {
       return v1.Value.CompareTo(v2.Value);
    }
    return v1 == null && v2 == null;
});

Note that both lists must be a list of Nullable<decimal> . Hope it helps.

UPDATE : I'd implement CrossAbove generic on two type arguments and keep receiving the comparison delegate:

bool CrossAbove<T1, T2>(IList<T1> values1, IList<T2> values2, Func<T1, T2, int> compare)

At the time of calling CrossAbove you'll know what T1 and T2 concrete types are and you can pass the correct comparison delegate. This is the way I'd go and I think it is shorter. An example with decimal and decimal? would be:

// Params: values1: List<decimal>, values2: List<decimal?>
CrossAbove(values1, values2, (x,y) => {
    if (y.HasValue) { return x.CompareTo(y.Value);}
    // Either give 1 or -1 depending on your logic.
    return 1;
});

you can use Nullable.Compare<T> like this:

Boolean CrossAbove<T>(IList<T?> values1, IList<T?> values2) where T : struct
{
    return 
        !values1.Reverse().Take(2).Any(x => !x.HasValue) &&
        !values2.Reverse().Take(2).Any(x => !x.HasValue) &&
        Nullable.Compare<T>(values1[values1.Count - 2],values2[values2.Count - 2]) < 0 
        && Nullable.Compare<T>(values1.Last(), values2.Last()) > 0;
}

However it makes comparison based on Nullable comparison described here which is different than what you expected. But you can make a little modification of you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM