0

I have a dictionary of "Title" objects in my C# code: Dictionary<long, Title> DAllTitles

With Title class define as follow:

    class Title
    {
        public long TitleID { get; set;}
        public string TitleText { get; set;}
        public string TitleNumber { get; set;}
    }

The "TitleNumber" can have these values for example: "1", "1.1", "2.10", "4.6.5.2.5" etc... It can be more numbers in the future.

How could i get a dictionary or list of titles ordered by the "TitleNumber" attribute from the dictionary DAllTitles? I can't think of a simple solution...

Thanks in advance!

Liam
  • 27,717
  • 28
  • 128
  • 190

3 Answers3

0

You can use a cheapo helper function:

string padded(string s)
{
    var p = s.Split('.');
    var pp = string.Join("." , p.Select(x => Convert.ToInt16(x).ToString("00000")));
    return pp;
}

and then sort with linq:

List<Title> sorted = DAllTitles.OrderBy(x => padded(x.TitleNumber)).ToList();

Some linq artists may even roll it all in one, but not me ;-)

Note that I omitted all checks! You can also skip one line in the function and return direcly and pick a maximum number of digitts in the string format..

input (slightly modifed class):

var DAllTitles = new List<Title>()
{
    new Title("1.20"),new Title("1.2"),new Title("1.11"),new Title("1.1"),new Title("1.1.1")
    ,new Title("1.1.0"),new Title("1.1.3")
};

output:

1.1
1.1.0
1.1.1
1.1.3
1.2
1.11
1.20
TaW
  • 53,122
  • 8
  • 69
  • 111
0

A class you could implement to more properly control the versioning.

public class TitleNumber : IComparable
{
    private int[] Version;

    public TitleNumber(string titlenumber)
    {
        Version = titlenumber.Split('.').Select(x => int.Parse(x)).ToArray();
    }

    public int CompareTo(object obj)
    {
        if (obj is TitleNumber other)
        {
            return CompareTo(other);
        }
        else
        {
            throw new ArgumentException($"Object must be of type {nameof(TitleNumber)}");
        }
    }

    public int CompareTo(TitleNumber other)
    {
        var depth = 0;
        var depthThis = Version.Length - 1;
        var depthOther = other.Version.Length - 1;
        while (true)
        {
            if (depthThis == depth && depthOther == depth) return 0;
            if (depthOther < depth || (depthThis >= depth && Version[depth] > other.Version[depth])) return 1;
            if (depthThis < depth || Version[depth] < other.Version[depth]) return -1;
            depth++;
        }
    }

    public override bool Equals(object obj) => obj is TitleNumber other && CompareTo(other) == 0;
    public override string ToString() => string.Join(".", Version);
}

With an example on how to use it:

var t1 = new TitleNumber("5.34.20");
var t2 = new TitleNumber("4");
var t3 = new TitleNumber("5.34");
var t4 = new TitleNumber("5.34.20.1");
var t5 = new TitleNumber("5.35");

var l = new List<TitleNumber>() { t1, t2, t3, t4, t5 };
var r = l.OrderBy(x => x).ToList();
NotFound
  • 5,005
  • 2
  • 13
  • 33
-1

I'm not sure I understand what rules you want to apply to your ordering logic, but to me LINQ can do what you want.

dico.OrderBy(kvp => kvp.Value.TitleNumber).ToDictionary(kvp => kvp.Key);

That will order your dictionary in a certain way, I don't doubt you could adapt it to your needs.

Miiite
  • 1,517
  • 10
  • 16
  • This will not work with 3.1, 3.10, 3.1.1 – Nicolas Daumalle Jan 25 '19 at 09:47
  • @NicolasDaumalle what is the order when concerning 3.1, 3.1.1, 3.11, 3.10 ? – Anu Viswan Jan 25 '19 at 09:49
  • I tested it with the following dictionary var dico = new Dictionary(){ { 1, new Title{ TitleID=10, TitleText="text10", TitleNumber="1.1" } }, { 2, new Title{ TitleID=20, TitleText="text20", TitleNumber="1.2" } }, { 3, new Title{ TitleID=30, TitleText="text30", TitleNumber="2.1" } }, { 4, new Title{ TitleID=40, TitleText="text40", TitleNumber="1.3" } }, { 5, new Title{ TitleID=50, TitleText="text50", TitleNumber="0.5" } }, }; and it outputs objects in the following order: 5, 1, 2, 4, 3 which looks correct to me – Miiite Jan 25 '19 at 10:15
  • It does work with values like "1.2.1" also – Miiite Jan 25 '19 at 10:17