MinMaxArray

O

Ondrej Medek

Hi,
I would like to have a generic class MinMaxArray<T>, which is a
wrapper around an array of T[] and computes minimum, maximum, and
average value from the array T[]. I need it only for the basic numeric
types (int, float, etc.).

I had problems with operators < > + and /, when I was computing
minimum, maximum and average values. I have errors like "Operator ...
cannot be applied to operans of type 'T' and 'T'." So, I use
IComparer<T> instead of operators < >, but I do not know, how to
compute average value (sum and divide) for a generic numeric type T.
Is there any easy way to do it? Disable the type checking in the
compile time?

Thx
 
M

Marc Gravell

You cannot disable the type checking. What runtime are you using? Note that
..NET 3.5 with LINQ includes extension methods that allow you to do this on a
regular array:

using System.Linq;
static class Program {
static void Main() {
int[] data = {1,2,3,4,5};
int min = data.Min(), max = data.Max(),
sum = data.Sum();
double avg = data.Average();
}
}

So my first thought is: use .NET 3.5 and C# 3.

There are various reasons why operators don't work on generics, discussed
here:
http://www.pobox.com/~skeet/csharp/genericoperators.html
In that article I also present a working (and fast) implementation of
generic maths via the Operator class, available in MiscUtil (with .NET 3.5).
http://www.pobox.com/~skeet/csharp/miscutil/usage/genericoperators.html
I did have a 2.0 version somewhere, but less tested - and I don't have it
"to hand".

Marc
 
M

Marc Gravell

Additional thought; in 2.0 you can do min/max very easily using
Comparer<T>.Default - the only tricky thing being deciding how you want to
handle nulls (Nullable<T> and/or references); do you want to skip them, or
just return null.

Marc
 
J

Jeroen Mostert

Ondrej said:
I would like to have a generic class MinMaxArray<T>, which is a
wrapper around an array of T[] and computes minimum, maximum, and
average value from the array T[]. I need it only for the basic numeric
types (int, float, etc.).
Arrays are immutable. Do you need a mutable collection? The values are easy
enough to calculate for any collection after it's created. LINQ offers
extension methods to do this directly, actually, so you can write
a.Average() for any array of numerical types. Incorporating this in a
wrapper to cache the calculated values is easy.
I had problems with operators < > + and /, when I was computing
minimum, maximum and average values. I have errors like "Operator ...
cannot be applied to operans of type 'T' and 'T'." So, I use
IComparer<T> instead of operators < >, but I do not know, how to
compute average value (sum and divide) for a generic numeric type T.
Is there any easy way to do it? Disable the type checking in the
compile time?
Basically, the .NET type system isn't extensive enough to do what you want
directly. There is no INumeric interface that all primitive numeric types
implement. IComparable and IEquatable are not sufficient for the operations
you want. You can use Decimal as a generic integral type, but there's no
equivalent for float and double.

In short, you can't really use generics here without resorting to ugly code
like this:

if (typeof(T) == typeof(int)) {
T result = (T) (((int) t1) / ((int) t2));
}

This works, but it's not winning any safety or readability prizes. There are
various ways of mitigating this, but they're all more or less trying to fit
a square peg in a round hole.
 
J

Jeroen Mostert

Jeroen said:
Ondrej said:
I would like to have a generic class MinMaxArray<T>, which is a
wrapper around an array of T[] and computes minimum, maximum, and
average value from the array T[]. I need it only for the basic numeric
types (int, float, etc.).
Arrays are immutable.

Well, in the sense that you can't change their size after construction. You
can, of course, change the elements in the array, which would affect the
aggregate values. Using "immutable" here is highly misleading.

Aside from the issues already discussed, if you need a collection that has
to update additional state when its elements change, you can derive from
Collection<T>.
 
M

Marc Gravell

Arrays are immutable.
Well, they can't be resized, but are definitely mutable regarding the
contents of an array... but I'm not quite sure how that relates to the
question, unless the OP wants to Add(), rathen than just swap items. Of
course, the LINQ approach will work the same on lists/collections/arrays,
which is nice.
There are various ways of mitigating this, but they're all more or less
trying to
fit a square peg in a round hole.

Other pegs are available ;-p
I guess Operator would be an "amost round" peg... some kind of icosagon or
similar - there are a few gaps, but it comes close...

Marc
 
J

Jeroen Mostert

Marc said:
Well, they can't be resized, but are definitely mutable regarding the
contents of an array... but I'm not quite sure how that relates to the
question, unless the OP wants to Add(), rathen than just swap items.

Yeah, I realized "immutable" was the wrong word to use (and I managed to
confuse myself as well). It was indeed thinking of a collection where you
add elements after the fact and want the aggregates to be updated
immediately, although then I realized that a mutable collection that can't
be resized is just as problematic.
Other pegs are available ;-p
I guess Operator would be an "amost round" peg... some kind of icosagon or
similar - there are a few gaps, but it comes close...
I like these "too clever by half" solutions on an intellectual level, but I
wouldn't actually stick them in my production code. No offense. :)

If I want C++, Smalltalk or Haskell (each of which would solve this problem
in its own distinct way) I know where to get them. For C#, LINQ's good
enough for me... Either that or maybe two specialized classes for Decimal
and Double.
 
M

Marc Gravell

No offense. :)
None taken.
For C#, LINQ's good enough for me...
In many cases, yes. Note that although it provides a generic Min<T>/Max<T>,
it doesn't provide generic methods for the more arithmetic-based methods.
But as you rightly saay - it is often enough.

Marc
 
O

Ondrej Medek

So my first thought is: use .NET 3.5 and C# 3.

Hmm, I use .NET 2.0. Maybe we'll upgrade later (we have a bigger
project).

So far, I've ended up with a few classes like MinMaxArrayFloat,
MinMaxArrayInt, and so on.

Thx for your informations.
 
J

Jon Skeet [C# MVP]

Hmm, I use .NET 2.0. Maybe we'll upgrade later (we have a bigger
project).

Could you use LINQBridge? You'd still need to upgrade to C# 3 which
means installing VS2008 on your dev boxes, but you wouldn't need to
upgrade your projects to use .NET 3.5.

Jon
 
M

Marc Gravell

So far, I've ended up with a few classes like MinMaxArrayFloat,
MinMaxArrayInt, and so on.

Pedant mode: you might want to name them accordingly to the .NET
types, rather than the C# aliases - MinMaxArraySingle,
MinMaxAraryInt32. This is probably only important if the assemby is
going to be consumed by a larger team (i.e. a community project, or if
you are an ISV, etc). That way, the names make sense even in VB etc.

Marc
 
O

Ondrej Medek

Pedant mode: you might want to name them accordingly to the .NET
types, rather than the C# aliases - MinMaxArraySingle,
MinMaxAraryInt32. This is probably only important if the assemby is
going to be consumed by a larger team (i.e. a community project, or if
you are an ISV, etc). That way, the names make sense even in VB etc.

Yeah, it makes sense.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top