Raymond Tunstill
Raymond Tunstill

Reputation: 109

Sorting a list of objects of multiple data types

I have this class in my code

class Stock
{
    public DateTime Date;
    public string Day;
    public double Open, Close, Diff;
    public int Volume;

    public Stock(double open, double close, double diff, int volume, string day, DateTime date)
    {
        this.Open = open;
        this.Close = close;
        this.Diff = diff;
        this.Volume = volume;
        this.Day = day;
        this.Date = date;
    }
}

In another class i want to create a bubble sort that will sort a List of Stocks (List<Stocks>) passed to it, i am having multiple issues with this the main problem is the data types, its not easy comparing two values when they could be a string, int, double or DateTime. I have done it with a method that uses TryParse to check for valid data type, but im looking for a nice clean solution, this is my attempt so far

public void BubblesortBy(int sortBy, List<Stock> Stocks)
{

    Type objType = typeof(Stock);
    FieldInfo[] fields = objType.GetFields();

    Stock temp = null;
    int loopCount = 0;
    bool doBreak = true;

    for (int i = 0; i < Stocks.Count; i++)
    {
        doBreak = true;
        for (int j = 0; j < Stocks.Count - 1; j++)
        {
            if (Compare(fields[sortBy - 1].FieldType.ToString(), fields[sortBy].GetValue(Stocks[j]), fields[sortBy].GetValue(Stocks[j+1])))
            {
                temp = Stocks[sortBy + 1];
                Stocks[sortBy + 1] = Stocks[sortBy];
                Stocks[sortBy] = temp;
                doBreak = false;
            }
            loopCount++;
        }
        if (doBreak) { break; /*early escape*/ }
    }
}

The int passed to it determines whether to sort by, which is why i am using reflection so the variables are accessible by numbers.

  1. Date
  2. Day
  3. Open
  4. Close
  5. Difference
  6. Volume

Upvotes: 0

Views: 2126

Answers (2)

Tim S.
Tim S.

Reputation: 56546

You shouldn't assume that the fields returned by GetFields will be in a certain order.

The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.

One option is to use lambdas like LINQ's OrderBy method does. Using generic types can also make your code more reusable, and make things like your Compare method simpler.

public void BubblesortBy<TSource, TKey>(Func<TSource, TKey> keySelector,
                                        List<TSource> stocks)
{
    int loopCount = 0;
    bool doBreak = true;

    for (int i = 0; i < stocks.Count; i++)
    {
        doBreak = true;
        for (int j = 0; j < stocks.Count - 1; j++)
        {
            if (Compare(keySelector(stocks[j]), keySelector(stocks[j+1])))
            {
                TSource temp = stocks[j + 1];
                stocks[j + 1] = stocks[j];
                stocks[j] = temp;
                doBreak = false;
            }
            loopCount++;
        }
        if (doBreak) { break; /*early escape*/ }
    }
}
private bool Compare<T>(T l, T r)
{
    return Comparer<T>.Default.Compare(l, r) > 0;
}

// use like
BubblesortBy(x => x.Close, myList);

Upvotes: 1

Michael Sander
Michael Sander

Reputation: 2737

Why are you implementing sorting yourself? Look into IComparable

Edit:

A nice and type safe way to pass the field to sort by into the method without refection, would be:

BubblesortBy(x => x.FieldName, stockes);

public void BubblesortBy<T>(Func<Product, T> sortBy, List<Stock> Stocks)
{
    Stock temp = null;
    int loopCount = 0;
    bool doBreak = true;

    for (int i = 0; i < Stocks.Count; i++)
    {
        doBreak = true;
        for (int j = 0; j < Stocks.Count - 1; j++)
        {
            if (Compare(sortBy(Stocks[j]), sortBy(Stocks[j + 1])))
            {
                temp = Stocks[sortBy + 1];
                Stocks[sortBy + 1] = Stocks[sortBy];
                Stocks[sortBy] = temp;
                doBreak = false;
            }
            loopCount++;
        }
        if (doBreak)
            break; /*early escape*/
    }
}

Upvotes: 1

Related Questions