" I created a template that returns the index of the maximum value in an array. It works, bu...">

"Double" does not display as "IComparable <Double>"

I created a template that returns the index of the maximum value in an array. It works, but only if I go to a weird list.

    static public int FindMaxIndex<T>( IEnumerable<IComparable<T>> arr )
    {
        IEnumerator<IComparable<T>> it = arr.GetEnumerator();
        if (!it.MoveNext()) return -1;
        int index = 1, maxIndex = 0;
        IComparable<T> max = it.Current;
        while (it.MoveNext())
        {
            if (max.CompareTo( (T)(it.Current) ) < 0)
            {
                maxIndex = index;
                max = it.Current;
            }
            ++index;
        }
        return maxIndex;
    }

      

Now use it:

    List<IComparable<Double>> arr = new List<IComparable<Double>>(); // THIS WORKS
    List<Double> arr = new List<Double>(); // THIS DOESN'T

      

A later list that I would like to use gives this compiler error:

cannot convert from 'System.Collections.Generic.List<double>' to 'System.Collections.Generic.IEnumerable<System.IComparable<double>>'

      

How can it be? "Double" is incompatible; taken from his definition:

public struct Double : IComparable, IFormattable, IConvertible, IComparable<Double>, IEquatable<Double>

+3


source to share


4 answers


I think the other answers have addressed the question of why your code as written does not work as you expected , and even why the code will not work in some cases . However, none of the answers show you a way to do what you want:

public static int FindMaxIndex<T>( IEnumerable<T> source ) where T : IComparable<T>
{
    using( var e = source.GetEnumerator() )
    {
        if( !e.MoveNext() ) return -1;

        T maxValue = e.Current;
        int maxIndex = 0;

        for( int i = 1; e.MoveNext(); ++i )
        {
            if( maxValue.CompareTo( e.Current ) < 0 )
            {
                maxIndex = i;
                maxValue = e.Current;
            }
        }

        return maxIndex;
    }
}

      

So, I introduced a generic constraint ( where T : IComparable<T>

) here. This tells the compiler that the T

implementation will happen regardless IComparable<T>

.

Also, I've put an enumerator in a statement using

that makes sure its method Dispose

is called.

Anyway, now when you call this method, it will work directly on IEnumerable<double>

and even infer the type parameter for you:



var someDoubles = new List<double> { 3, 2, 1 };
Console.WriteLine( FindMaxIndex( someDoubles ) ) // Prints "0";

      

Also, if FindMaxIndex

declared in a class static

, you can put a keyword this

in front of the original parameter to make it an extension method:

public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
    // ...
}

      

You should now be able to call it like this:

list.FindMaxIndex()

      

+4


source


Shared covariance is only valid when the shared argument is a reference type. Since you have a value type as an argument, it cannot perform covariant conversions.



+3


source


double

is IComparable<double>

but is List<double>

not List<IComparable<double>>

.

And it cannot be allowed. Consider:

private class ScrewItUp : IComparable<double>
{
    public int CompareTo(double value) => 0;
}

List<IComparable<double>> list = new List<double>(); // you propose that this work.
list.Add(new ScrewItUp()); // What this supposed to do, then?

      

On can have variance associated with interfaces, so that, for example, List<string>

can be passed to IEnumerable<object>

, but this can only happen when the types participating in the variance are reference types.

+3


source


John Hannah's answer is in the right direction. Below is the code.

double

maybe IComparable<double>

. However, a is List<double>

not List<IComparable<double>>

. Each item inside the list requires. You cannot use the entire list.

List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<double>>()));

      

-2


source







All Articles