Reputation: 59
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.
Upvotes: 0
Views: 749
Reputation: 933
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();
}
}
}
Upvotes: 0
Reputation: 152501
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 ;
Upvotes: 2
Reputation: 12797
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]);
}
}
Upvotes: 2