How to sort an arraylist on date? - c#

Code:
while ((linevalue = filereader.ReadLine()) != null)
{
items.Add(linevalue);
}
filereader.Close();
items.Sort();
//To display the content of array (sorted)
IEnumerator myEnumerator = items.GetEnumerator();
while (myEnumerator.MoveNext())
{
Console.WriteLine(myEnumerator.Current);
}
The program above displays all the values. How to extract only the dates and sort it in ascending order?
I am not let to work with linq, use the exception or threading or any other stuff. I have to stick with the File Stream, try to get my data out of the text file, sort and store it, so that i can retrieve it, view it and edit it and search for any particular date and see the date of joining records for that date. Can't figure out. Struggling

Basically, don't try and work with the file as lines of text; separate that away, so that you have one piece of code which parses that text into typed records, and then process those upstream when you only need to deal with typed data.
For example (and here I'm assuming that the file is tab-delimited, but you could change it to be column indexed instead easily enough); look at how little work my Main method needs to do to work with the data:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
static class Program
{
static void Main()
{
foreach (var item in ReadFile("my.txt").OrderBy(x => x.Joined))
{
Console.WriteLine(item.Names);
}
}
static readonly char[] tab = { '\t' };
class Foo
{
public string Names { get; set; }
public int Age { get; set; }
public string Designation { get; set; }
public DateTime Joined { get; set; }
}
static IEnumerable<Foo> ReadFile(string path)
{
using (var reader = File.OpenText(path))
{
// skip the first line (headers), or exit
if (reader.ReadLine() == null) yield break;
// read each line
string line;
var culture = CultureInfo.InvariantCulture;
while ((line = reader.ReadLine()) != null)
{
var parts = line.Split(tab);
yield return new Foo
{
Names = parts[0],
Age = int.Parse(parts[1], culture),
Designation = parts[2],
Joined = DateTime.Parse(parts[3], culture)
};
}
}
}
}
And here's a version (not quite as elegant, but working) that works on .NET 2.0 (and probably on .NET 1.1) using only ISO-1 language features; personally I think it would be silly to use .NET 1.1, and if you are using .NET 2.0, then List<T> would be vastly preferable to ArrayList. But this is "worst case":
using System;
using System.Collections;
using System.Globalization;
using System.IO;
class Program
{
static void Main()
{
ArrayList items = ReadFile("my.txt");
items.Sort(FooByDateComparer.Default);
foreach (Foo item in items)
{
Console.WriteLine(item.Names);
}
}
class FooByDateComparer : IComparer
{
public static readonly FooByDateComparer Default
= new FooByDateComparer();
private FooByDateComparer() { }
public int Compare(object x, object y)
{
return ((Foo)x).Joined.CompareTo(((Foo)y).Joined);
}
}
static readonly char[] tab = { '\t' };
class Foo
{
private string names, designation;
private int age;
private DateTime joined;
public string Names { get { return names; } set { names = value; } }
public int Age { get { return age; } set { age = value; } }
public string Designation { get { return designation; } set { designation = value; } }
public DateTime Joined { get { return joined; } set { joined = value; } }
}
static ArrayList ReadFile(string path)
{
ArrayList items = new ArrayList();
using (StreamReader reader = File.OpenText(path))
{
// skip the first line (headers), or exit
if (reader.ReadLine() == null) return items;
// read each line
string line;
CultureInfo culture = CultureInfo.InvariantCulture;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(tab);
Foo foo = new Foo();
foo.Names = parts[0];
foo.Age = int.Parse(parts[1], culture);
foo.Designation = parts[2];
foo.Joined = DateTime.Parse(parts[3], culture);
items.Add(foo);
}
}
return items;
}
}

I'm not sure why you'd want to retrieve just the dates. You'd probably be better reading your data into Tuples first. Something like
List<Tuple<string, int, string, DateTime>> items.
Then you can sort them by items.Item4, which will be the date.

You can use LINQ and split the line according to tabs to only retrieve the date and order them through a conversion to date.
while ((linevalue = filereader.ReadLine()) != null)
{
items.Add(linevalue.Split('\t').Last());
}
filereader.Close();
items.OrderBy(i => DateTime.Parse(i));
foreach(var item in items)
{
Console.WriteLine(item);
}

get the desired values in Array from the file...
public class DateComparer : IComparer {
public int Compare(DateTime x, DateTime y) {
if(x.Date > y.Date)
return 1;
if(x.Date < y.Date)
return -1;
else
return 0;
}
}
list.Sort(new DateComparer());

Related

Trie implementation: Search method with weird return value

I am fairly new to C# and working on a project in which I need to build a prefix tree (trie). Searching in the trie should return a list of words matching a given search prefix.
That's the code I have so far, but the search doesnt actually return the value I'm looking for and instead returns "Trees.PrefixTree+d__5". What am I doing wrong or what do I have to change to get it run?
Thank you very much in advance!
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace Trees
{
public class Program
{
public static void Main()
{
//String[] file = File.ReadAllLines(#"C:\Users\samue\Desktop\Neuer Ordner (2)\liste.txt");
string[] dictionary = new string[] { "test", "try", "angle", "the", "code", "is", "isnt" };
PrefixTree trie = new PrefixTree();
var sw = new Stopwatch();
foreach (var word in dictionary)
{
trie.Add(word);
}
//Thread workerThread = new Thread(trie.Search(suchwort);
Console.WriteLine(trie.Search("te"));
}
}
public class PrefixTree
{
private PrefixTreeNode root;
public PrefixTree()
{
root = new PrefixTreeNode(String.Empty);
}
public void Add(string word)
{
AddRecursive(root, word, String.Empty);
}
private void AddRecursive(PrefixTreeNode node, string remainingString, string currentString)
{
if (remainingString.Length <= 0)
{
return;
}
char prefix = remainingString[0];
string substring = remainingString.Substring(1);
if (!node.SubNodes.ContainsKey(prefix))
{
node.SubNodes.Add(prefix, new PrefixTreeNode(currentString + prefix));
}
if (substring.Length == 0)
{
node.SubNodes[prefix].IsWord = true;
return;
}
else
{
AddRecursive(node.SubNodes[prefix], substring, currentString + prefix);
}
}
public IEnumerable<string> Search(string searchString)
{
PrefixTreeNode node = root;
foreach (var search in searchString)
{
if (!node.SubNodes.ContainsKey(search))
{
return new string[0];
}
node = node.SubNodes[search];
}
return FindAllWordsRecursive(node);
}
private IEnumerable<string> FindAllWordsRecursive(PrefixTreeNode node)
{
if (node.IsWord)
{
yield return node.Word;
}
foreach (var subnode in node.SubNodes)
{
foreach (var result in FindAllWordsRecursive(subnode.Value))
{
yield return result;
}
}
}
protected class PrefixTreeNode
{
private readonly Dictionary<char, PrefixTreeNode> subNodes;
private bool isWord;
private readonly string word;
public PrefixTreeNode(string word)
{
subNodes = new Dictionary<char, PrefixTreeNode>();
isWord = false;
this.word = word;
}
public Dictionary<char, PrefixTreeNode> SubNodes { get { return subNodes; } }
public bool IsWord { get { return isWord; } set { isWord = value; } }
public string Word { get { return word; } }
}
}
}
Try changing your Console.WriteLine() to this:
Console.WriteLine(string.Join(", ", trie.Search("te")));
You were not concatenating all the strings together!

C# How to add string to a list from a different file

I'm new to C# and OOP I have two different files. File A where I've created the list.
//This file will contain predetermine list of responses.
using System.Linq;
using System.Collections.Generic;
public class Responses
{
//bot name
static string nomber = "Jarvis";
List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public void AddToList(string value){
this.answer.Add(value);
}
public string Answer(int id)
{
return answer.ElementAt(id);
}
}
And in file B I have these two lines of code to add the string 1 to the list, I've also included the Generics and Linq System in file B.
var response = new Responses();
response.answer.Add("1");
I've tried creating a method called AddToList to pass the value and add it to the list, but with no luck. When I try to display the list at index 2 I'll get an argument out of range instead of the value "1".
*Also both files are located in the same folder.
After read your source code, I understand your problem. First you Add new element to Response.answers of Interperter and it return id then you get Response.answer of Output by that id. Of course you never get that, because they were 2 different instances.
I provide 2 options for you:
Option 1: Make Reponses single instance (singleton)
Responses.cs
using System.Linq;
using System.Collections.Generic;
public class Responses
{
private static Responses _instance = new Responses();
public static GetInstance() {
return _instance;
}
//bot name
static string nomber = "Jarvis";
List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public void AddToList(string value){
this.answer.Add(value);
}
public string Answer(int id)
{
return answer.ElementAt(id);
}
}
Then change on other files
//from
var responses = new Responses();
//to
var responses = Responses.GetInstance();
//from
responses.answer.Add()
//to
reponses.AddToList()
Option 2: Make Responses static
Response.cs
using System.Linq;
using System.Collections.Generic;
public static class Responses
{
//bot name
static string nomber = "Jarvis";
static List<string> answer = new List<string>(){
$"Mi nomber ta {nomber}",
"Mi ta bon"
};
public static void AddToList(string value){
this.answer.Add(value);
}
public static string Answer(int id)
{
return answer.ElementAt(id);
}
}
Output.cs
using System;
public class Output
{
public void Return(int respondType, int respond)
{
switch(respondType)
{
case 0:
Console.WriteLine(Responses.Answer(respond));
break;
default:
Console.WriteLine("Mi no ta kompronde");
break;
}
}
}
Interperter.cs
using System.Collections.Generic;
using System.Linq;
public class Interpreter
{
public int UserInputType(string value)
{
// Turns the user input into an array of words
string[] words = value.Split(' ');
int returnValue = 2;
//int match = 0;
Responses.AddToList("1");
//This stores the correct response to the given question
//var element = new List<int>();
foreach(var word in words)
{
// if(!string.IsNullOrWhiteSpace(word))
// {
foreach(var listOfQuestions in userInputedQuestions)
{
//Convert words in the listOfQuestions to array string to match them with the userInputedQuestion
string[] listOfQWords = listOfQuestions.Split(" ");
//Check how many words matches the predefined list of questions
foreach(var qWord in listOfQWords){
if(word == qWord){
returnValue = 0;
}
}
}
}
// }
return returnValue;
}
private List<string> userInputedQuestions = new List<string>(){
"Ki ta bo nomber?",
"Konta ku bo?"
};
}
Hope it helps

Converting dot notation strings to multidimensional arrays

Does anyone know of a C# equivalent of this occassional PHP task:
Convert dot syntax like "this.that.other" to multi-dimensional array in PHP
That is, to convert a list of strings like level1.level2.level3 = item into a dictionary or multidimensional array?
I'd assume the dictionary would need to hold items of type object and I'd later cast them to Dictionary<string, string> or a string if it's a final item.
Does code like this work?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "level1.level2.level3 = item";
string pattern = "^(?'keys'[^=]+)=(?'value'.*)";
Match match = Regex.Match(input, pattern);
string value = match.Groups["value"].Value.Trim();
string[] keys = match.Groups["keys"].Value.Trim().Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
foreach (string key in keys)
{
if (dict.ContainsKey("key"))
{
dict[key].Add(value);
}
else
{
dict.Add(key, new List<string>() { value });
}
}
}
}
}
I guess you could do it like this, though (i'm sure more optimization could be done)
using System;
using System.Collections.Generic;
public class Program
{
public class IndexedTree {
private readonly IDictionary<string, IndexedTree> _me;
private object _value;
private readonly string _splitKey = ".";
public IndexedTree this[string key] {
get {
return _me[key];
}
}
public object Value { get; set; }
public void Add(string dottedItem) {
if ( string.IsNullOrWhiteSpace( dottedItem ) ) {
throw new ArgumentException("dottedItem cannot be empty");
}
int index;
if ( (index = dottedItem.IndexOf( _splitKey ) ) < 0 ) {
throw new ArgumentException("dottedItem didn't contain " + _splitKey);
}
string key = dottedItem.Substring(0, index), rest = dottedItem.Substring(index + 1);
IndexedTree child;
if (_me.ContainsKey(key)) {
child = _me[key];
} else {
child = new IndexedTree( _splitKey );
_me.Add(key, child);
}
if (rest.IndexOf(_splitKey) >= 0) {
child.Add(rest);
} else {
// maybe it can be checked if there is already a value set here or not
// in case there is a warning or error might be more appropriate
child.Value = rest;
}
}
public IndexedTree(string splitKey) {
_splitKey = splitKey;
_me = new Dictionary<string, IndexedTree>();
}
}
public static void Main()
{
IndexedTree tree = new IndexedTree(".");
tree.Add("Level1.Level2.Level3.Item");
tree.Add("Level1.Level2.Value");
Console.WriteLine(tree["Level1"]["Level2"].Value);
Console.WriteLine(tree["Level1"]["Level2"]["Level3"].Value);
}
}
You could see the result here:
https://dotnetfiddle.net/EGagoz

Writing enumerable to csv file

I'm sure its very straightforward but I am struggling to figure out how to write an array to file using CSVHelper.
I have a class for example
public class Test
{
public Test()
{
data = new float[]{0,1,2,3,4};
}
public float[] data{get;set;}
}
i would like the data to be written with each array value in a separate cell. I have a custom converter below which is instead providing one cell with all the values in it.
What am I doing wrong?
public class DataArrayConverter<T> : ITypeConverter
{
public string ConvertToString(TypeConverterOptions options, object value)
{
var data = (T[])value;
var s = string.Join(",", data);
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
throw new NotImplementedException();
}
public bool CanConvertFrom(Type type)
{
return type == typeof(string);
}
public bool CanConvertTo(Type type)
{
return type == typeof(string);
}
}
To further detail the answer from Josh Close, here what you need to do to write any IEnumerable (including arrays and generic lists) in a recent version (anything above 3.0) of CsvHelper!
Here the class under test:
public class Test
{
public int[] Data { get; set; }
public Test()
{
Data = new int[] { 0, 1, 2, 3, 4 };
}
}
And a method to show how this can be saved:
static void Main()
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
var list = new List<Test>
{
new Test()
};
csv.Configuration.HasHeaderRecord = false;
csv.WriteRecords(list);
writer.Flush();
}
}
The important configuration here is csv.Configuration.HasHeaderRecord = false;. Only with this configuration you will be able to see the data in the csv file.
Further details can be found in the related unit test cases from CsvHelper.
In case you are looking for a solution to store properties of type IEnumerable with different amounts of elements, the following example might be of any help:
using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CsvHelperSpike
{
class Program
{
static void Main(string[] args)
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
csv.Configuration.Delimiter = ";";
var list = new List<AnotherTest>
{
new AnotherTest("Before String") { Tags = new List<string> { "One", "Two", "Three" }, After="After String" },
new AnotherTest("This is still before") {After="after again", Tags=new List<string>{ "Six", "seven","eight", "nine"} }
};
csv.Configuration.RegisterClassMap<TestIndexMap>();
csv.WriteRecords(list);
writer.Flush();
}
using(var reader = new StreamReader("db.csv"))
using(var csv = new CsvReader(reader))
{
csv.Configuration.IncludePrivateMembers = true;
csv.Configuration.RegisterClassMap<TestIndexMap>();
var result = csv.GetRecords<AnotherTest>().ToList();
}
}
private class AnotherTest
{
public string Before { get; private set; }
public string After { get; set; }
public List<string> Tags { get; set; }
public AnotherTest() { }
public AnotherTest(string before)
{
this.Before = before;
}
}
private sealed class TestIndexMap : ClassMap<AnotherTest>
{
public TestIndexMap()
{
Map(m => m.Before).Index(0);
Map(m => m.After).Index(1);
Map(m => m.Tags).Index(2);
}
}
}
}
By using the ClassMap it is possible to enable HasHeaderRecord (the default) again. It is important to note here, that this solution will only work, if the collection with different amounts of elements is the last property. Otherwise the collection needs to have a fixed amount of elements and the ClassMap needs to be adapted accordingly.
This example also shows how to handle properties with a private set. For this to work it is important to use the csv.Configuration.IncludePrivateMembers = true; configuration and have a default constructor on your class.
Unfortunately, it doesn't work like that. Since you are returning , in the converter, it will quote the field, as that is a part of a single field.
Currently the only way to accomplish what you want is to write manually, which isn't too horrible.
foreach( var test in list )
{
foreach( var item in test.Data )
{
csvWriter.WriteField( item );
}
csvWriter.NextRecord();
}
Update
Version 3 has support for reading and writing IEnumerable properties.

Sort XML Nodes by Alpha.Numeric using C#

Say I have an XmlDocument that I generate that has InnerXml that looks like this:
<ORM_O01>
<MSH>
<MSH.9>
<MSG.2>O01</MSG.2>
</MSH.9>
<MSH.6>
<HD.1>13702</HD.1>
</MSH.6>
</MSH>
<ORM_O01.PATIENT>
<PID>
<PID.18>
<CX.1>SecondTestFin</CX.1>
</PID.18>
<PID.3>
<CX.1>108</CX.1>
</PID.3>
</PID>
</ORM_O01.PATIENT>
</ORM_O01>
As you can see node <PID.18> is before node <PID.3>. (<MSH.9> is also before <MSH.6>.)
Restructuring my generation would cause my nice clean code to become very messy.
Is there a way to sort the nodes so that it will sort alpha until it hits the last period then sort numeric (if the last values are numbers)?
By "numeric sorting" I mean it will look at the whole number rather than char by char. (So 18 > 3).
The obvious answer is yes.
If this is the result you want:
<ORM_O01>
<MSH>
<MSH.6>
<HD.1>13702</HD.1>
</MSH.6>
<MSH.9>
<MSG.2>O01</MSG.2>
</MSH.9>
</MSH>
<ORM_O01.PATIENT>
<PID>
<PID.3>
<CX.1>108</CX.1>
</PID.3>
<PID.18>
<CX.1>SecondTestFin</CX.1>
</PID.18>
</PID>
</ORM_O01.PATIENT>
</ORM_O01>
Then this class will do it: (I should get paid for this...)
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Test
{
public class SortXmlFile
{
XElement rootNode;
public SortXmlFile(FileInfo file)
{
if (file.Exists)
rootNode = XElement.Load(file.FullName);
else
throw new FileNotFoundException(file.FullName);
}
public XElement SortFile()
{
SortElements(rootNode);
return rootNode;
}
public void SortElements(XElement root)
{
bool sortWithNumeric = false;
XElement[] children = root.Elements().ToArray();
foreach (XElement child in children)
{
string name;
int value;
// does any child need to be sorted by numeric?
if (!sortWithNumeric && Sortable(child, out name, out value))
sortWithNumeric = true;
child.Remove(); // we'll re-add it in the sort portion
// sorting child's children
SortElements(child);
}
// re-add children after sorting
// sort by name portion, which is either the full name,
// or name that proceeds period that has a numeric value after the period.
IOrderedEnumerable<XElement> childrenSortedByName = children
.OrderBy(child =>
{
string name;
int value;
Sortable(child, out name, out value);
return name;
});
XElement[] sortedChildren;
// if needed to sort numerically
if (sortWithNumeric)
{
sortedChildren = childrenSortedByName
.ThenBy(child =>
{
string name;
int value;
Sortable(child, out name, out value);
return value;
})
.ToArray();
}
else
sortedChildren = childrenSortedByName.ToArray();
// re-add the sorted children
foreach (XElement child in sortedChildren)
root.Add(child);
}
public bool Sortable(XElement node, out string name, out int value)
{
var dot = new char[] { '.' };
name = node.Name.ToString();
if (name.Contains("."))
{
string[] parts = name.Split(dot);
if (Int32.TryParse(parts[1], out value))
{
name = parts[0];
return true;
}
}
value = -1;
return false;
}
}
}
Someone may be able to write this cleaner and meaner, but this should get you going.
Was interested in your question so here is my two cents.
I've implemented IComparer<T> to handle the element comparisons and two methods which handle recursion. The code could be cleaned up a bit but I've pasted in the console application code I created to show you my solution which I think worked out well.
Edit: To make this easier to read I've broken this down into the core parts though I've left the functional console app
IComparer<T> Implementation:
public class SplitComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var partsOfX = x.Split('.');
int firstNumber;
if (partsOfX.Length > 1 && int.TryParse(partsOfX[1], out firstNumber))
{
var secondNumber = Convert.ToInt32(y.Split('.')[1]);
return firstNumber.CompareTo(secondNumber);
}
return x.CompareTo(y);
}
}
Methods for handling the recursion:
private static XElement Sort(XElement element)
{
var xe = new XElement(element.Name, element.Elements().OrderBy(x => x.Name.ToString(), new SplitComparer()).Select(x => Sort(x)));
if (!xe.HasElements)
{
xe.Value = element.Value;
}
return xe;
}
private static XDocument Sort(XDocument file)
{
return new XDocument(Sort(file.Root));
}
Functional Console Application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var xml = #"<ORM_O01>
<ORM_O01.PATIENT>
<PID>
<PID.18>
<CX.1>SecondTestFin</CX.1>
</PID.18>
<PID.3>
<CX.1>108</CX.1>
</PID.3>
</PID>
</ORM_O01.PATIENT>
<MSH>
<MSH.9>
<MSG.2>O01</MSG.2>
</MSH.9>
<MSH.6>
<HD.1>13702</HD.1>
</MSH.6>
</MSH>
</ORM_O01>";
var xDoc = XDocument.Parse(xml);
var result = Sort(xDoc);
Console.WriteLine(result.ToString());
Console.Read();
}
private static XElement Sort(XElement element)
{
var xe = new XElement(element.Name, element.Elements().OrderBy(x => x.Name.ToString(), new SplitComparer()).Select(x => Sort(x)));
if (!xe.HasElements)
{
xe.Value = element.Value;
}
return xe;
}
private static XDocument Sort(XDocument file)
{
return new XDocument(Sort(file.Root));
}
}
public class SplitComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var partsOfX = x.Split('.');
int firstNumber;
if (partsOfX.Length > 1 && int.TryParse(partsOfX[1], out firstNumber))
{
var secondNumber = Convert.ToInt32(y.Split('.')[1]);
return firstNumber.CompareTo(secondNumber);
}
return x.CompareTo(y);
}
}
}
utilizing System.Xml.Linq, this code may help you.
Usage:
string xmlString=
#"
....your string.....
";
XDocument xDoc = XDocument.Load(new StringReader(xmlString));
XDocument newXDoc = SortXml(xDoc);
Console.WriteLine(newXDoc);
SortXml function:
XDocument SortXml(XDocument xDoc)
{
Func<XElement, string> keyBuilder =
s => s.Name.ToString().Split('.')
.Aggregate("",(sum, str) => sum += str.PadLeft(32,' '));
XElement root = new XElement(xDoc.Root.Name);
SortXml(root, xDoc.Elements(), keyBuilder);
return new XDocument(root);
}
void SortXml(XElement newXDoc, IEnumerable<XElement> elems, Func<XElement, string> keyBuilder)
{
foreach (var newElem in elems.OrderBy(e => keyBuilder(e)))
{
XElement t = new XElement(newElem);
t.RemoveNodes();
newXDoc.Add(t);
SortXml(t, newElem.Elements(), keyBuilder);
}
}
Yet another attempt, using a modified Dotnet.Commons.Xml.
Get the XmlUtils class here.
Create a custom Comparer that has all your logic (this will get you going)
public class CustomComparer : IComparer
{
public int Compare(object x, object y)
{
string o1 = x as string;
string o2 = y as string;
string[] parts1 = o1.Split('.');
string[] parts2 = o2.Split('.');
// Assuming first part is alpha, last part is numeric and both of them has second part. Otherwise compare original ones.
if (parts1.Length < 2 || parts2.Length < 2)
return o1.CompareTo(o2);
if (parts1[0].Equals(parts2[0]))
{
// Do a numeric compare
return int.Parse(parts1[parts1.Length - 1]).CompareTo(int.Parse(parts2[parts2.Length - 1]));
}
else
{
// Just compare the first part
return parts1[0].CompareTo(parts2[0]);
}
}
Then modify the XmlUtils SortElements function, add this to the top:
CustomComparer comparer = new CustomComparer();
and change the line:
if (String.Compare(node.ChildNodes[i].Name, node.ChildNodes[i-1].Name, true) < 0)
to
if (comparer.Compare(node.ChildNodes[i].Name, node.ChildNodes[i - 1].Name) < 0)
Would this solution from Java2S.com be of any use?

Categories