0

I am trying to sort an array of tab-delimited strings. I call the split function on tab characters on each element to break the strings into string arrays. I then do a comparison on the date element to return the order that they should be in. If the dates are equal I do a secondary comparison on a string field. My implementation of the IComparer interface looks like this:

class CompareLines : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string[] bSplitX = x.Split('\t');
        string[] bSplitY = y.Split('\t');

        int bYearX = Int32.Parse(bSplitX[4].Substring(4, 4));
        int bMonthX = Int32.Parse(bSplitX[4].Substring(0, 2));
        int bDayX = Int32.Parse(bSplitX[4].Substring(2, 2));

        int bYearY = Int32.Parse(bSplitY[4].Substring(4, 4));
        int bMonthY = Int32.Parse(bSplitY[4].Substring(0, 2));
        int bDayY = Int32.Parse(bSplitY[4].Substring(2, 2));

        DateTime bTempDateX = new DateTime(bYearX, bMonthX, bDayX);
        DateTime bTempDateY = new DateTime(bYearY, bMonthY, bDayY);

        if (DateTime.Compare(bTempDateX, bTempDateY) > 0)
        {
            return 1;
        }
        else if (DateTime.Compare(bTempDateX, bTempDateY) < 0)
        {
            return -1;
        }
        else if (DateTime.Compare(bTempDateX, bTempDateY) == 0)
        {
            if (String.Compare(bSplitX[3], bSplitY[3]) > 0)
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
        else
        {
            Console.WriteLine("ahhh wtf"); //should never be reached. This message has never appeared in my console.
            return 0;
        }
    }
}

My problem is that it will work sometimes and not others. Does anyone have any reasons why the above code would not work 100% of the time?

This has been hurting my brain for a couple days now and I really do not understand why it is not working.

7
  • 1
    What happens if it does not work? Commented Mar 21, 2014 at 13:50
  • 3
    Why are you parsing dates yourself, rather than using DateTime.ParseExact? And how do you expect us to help you without any information about the input, expected output, or what happens when it goes wrong? Commented Mar 21, 2014 at 13:51
  • I wasn't aware of ParseExact. Input is an array of strings. The relevant fields are a string (element at position 4) representing a date in MMddyyyy format and an arbitrary string to compare against if the dates are equal (element at position 3. Examples could be "f" "e" "c", etc. They can have more than one character though which is why they're strings) Expected output is the array sorted in ascending order by date, and secondarily by the string if dates match. I'm not sure exactly what's going wrong. Dates are in order to a certain point and then undefined (could go 2008 to 2010 to 2009) Commented Mar 21, 2014 at 13:57
  • You realize these dates are in the mathematically optimal format for comparison? One second, I'll demonstrate what I mean... Commented Mar 21, 2014 at 14:03
  • @Dave yyyyMMdd would be optimal for comparison and was actually what I was doing before but it was still not working. I may change it back to the int comparison instead of creating DateTime objects to improve performance. Commented Mar 21, 2014 at 14:05

3 Answers 3

2

The only hole I see is if the date and string are the same then you are not returning 0:

        if (String.Compare(bSplitX[3], bSplitY[3]) > 0) {
            return 1;
        } else {
            return -1;  // if they are equal it will return -1.
        }

That will throw off the sorting routine.

Here's a cleaner version:

   int dateCompare = DateTime.Compare(bTempDateX, bTempDateY);

   if (dateCompare == 0) 
        return String.Compare(bSplitX[3], bSplitY[3]);
   else
       return dateCompare ;
Sign up to request clarification or add additional context in comments.

Comments

2

How about replacing

if (String.Compare(bSplitX[3], bSplitY[3]) > 0) {
  return 1;
} else {
  return -1;
}

with

return String.Compare(bSplitX[3], bSplitY[3]);

Your current code in case of equal X and Y strings says that Y is smaller than X. The following is the code with ParseExact method.

class CompareLines : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string[] bSplitX = x.Split('\t');
        string[] bSplitY = y.Split('\t');

        DateTime bTempDateX = DateTime.ParseExact(bSplitX[4], "MMddyyyy", null);
        DateTime bTempDateY = DateTime.ParseExact(bSplitY[4], "MMddyyyy", null);

        if (DateTime.Compare(bTempDateX, bTempDateY) > 0)
            return 1;
        else if (DateTime.Compare(bTempDateX, bTempDateY) < 0)
            return -1;
        else
            return String.Compare(bSplitX[3], bSplitY[3]);
    }
}

2 Comments

You should explain why this change is important.
I think this may have worked. Initial pass put them in the correct order. Let me do a couple more tests and if it works, I'll mark this as an answer.
0

For one, you don't need to rewrite the compare logic built into the framework, it already returns what you're expecting so long as you set up the data properly first-hand. As Jon suggested, simply parse the dates then, return the comparison of the dates. I added a property IncomingFormat which may not be useful considering your input.

Edit: more succinct/clear:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;

namespace ConsoleApplication1
{
    public class CompareLines : IComparer<string>
    {
        public string IncomingFormat { get; set; }

        public int Compare(string first, string second)
        {
            var date1 = DateTime.ParseExact(first, IncomingFormat, CultureInfo.InvariantCulture);
            var date2 = DateTime.ParseExact(second, IncomingFormat, CultureInfo.InvariantCulture);

            return date1.CompareTo(date2);
        }
    }

    internal class Program
    {
        private static void Main()
        {
            const string dataFormat = "MM\tdd\tyyyy";

            var comparer = new CompareLines
            {
                IncomingFormat = dataFormat
            };

            int result;
            string date1, date2;

            date1 = DateTime.Parse("1/1/2000").ToString(dataFormat);
            date2 = DateTime.Parse("1/1/2000").ToString(dataFormat);
            result = comparer.Compare(date1, date2);
            Debug.Assert(result == 0);
            Console.WriteLine("{0} compare {1} = {2}", date1, date2, result);

            date1 = DateTime.Parse("1/1/2000").ToString(dataFormat);
            date2 = DateTime.Parse("1/2/2000").ToString(dataFormat);
            result = comparer.Compare(date1, date2);
            Debug.Assert(result == -1);
            Console.WriteLine("{0} compare {1} = {2}", date1, date2, result);

            date1 = DateTime.Parse("1/2/2000").ToString(dataFormat);
            date2 = DateTime.Parse("1/1/2000").ToString(dataFormat);
            result = comparer.Compare(date1, date2);
            Debug.Assert(result == 1);
            Console.WriteLine("{0} compare {1} = {2}", date1, date2, result);

            Console.ReadLine();
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.