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.