Manish Jain
Manish Jain

Reputation: 9649

Sort on list of objects that contains dictionary

Here is my object:

public class A
{
public string Name { get; set; }    
public Dictionary<int, List<int>> Years { get; set; }
}

Dictionary contains list of years then, list of months. I am looking to sort list of A by year first then month.

Dictionary sample on each A:

{2015,new List(){3,4,5,6}}
{2016,new List(){2,8,9,10}}

If I have multiple years then it can sort something like: 2015 then 2015, 2016 then 2016

I failed to implement IComparable or use any existing extension methods like OrderBy or Sort. Thanks!

Upvotes: 2

Views: 112

Answers (2)

cechode
cechode

Reputation: 1022

I added IComparable to your A class ( which of course you can extract and pass as a delegate .....)

fiddlerlink

note: For simplicity i DO assume that the lists are sorted. otherwise add a your sorts at the appropriate place in your scenario :)

basically return the first compare that is not equal years or months. you can call this by MyListOfAs.Sort();

public class A:IComparable<A>
{
    public string Name { get; set; }
    public Dictionary<int, List<int>> Years { get; set; }

    private int complists(List<int> a, List<int> b)
    {
        var iret = (from i in Enumerable.Range(0, Math.Min(a.Count, b.Count))
                     where a[i].CompareTo(b[i]) != 0
                     select a[i] > b[i] ? 1 : -1).FirstOrDefault();

        return iret;
    }
    public int CompareTo(A other)
    {
        var mykeys = this.Years.Keys.ToList();
        var otherkeys = other.Years.Keys.ToList();

        var iret = (from i in Enumerable.Range(0, Math.Min(mykeys.Count, otherkeys.Count))
                     let yearDiff = mykeys[i].CompareTo(otherkeys[i])
                     let monthDiff = complists(this.Years[mykeys[0]], other.Years[otherkeys[0]])
                     where yearDiff != 0 || monthDiff != 0
                     select yearDiff != 0 ? yearDiff : monthDiff).FirstOrDefault();

        return iret != 0 ? iret : mykeys.Count > otherkeys.Count ? 1 : mykeys.Count < otherkeys.Count ? -1 : 0;
    }    }

Upvotes: 1

YoryeNathan
YoryeNathan

Reputation: 14512

I think this should do it: listOfA.OrderBy(a => a.Years.Min(y => y.Key + y.Value.Min() / 13d))

If the lowest year and month in a dictionary is 2000 Jan, for example, it's value would be 2000 + 1/13 = 2000.0769

Then all that's left is to select the smallest value from each dictionary, and sort them by that.

Note that the value 13 can be 20 as well, if you want nicer numbers for some reason, but the biggest fraction of 12/x must be less than 1 in order to give more importance to the year properly, so x must be greater than 12. This assumes that the range of the months is 1 to 12 inclusively.


Example I/O:

var listOfA = new List<A>
              {
                  new A
                  {
                      Name = "a1",
                      Years = new Dictionary<int, List<int>>
                              {
                                  {2015, new List<int> {3, 4, 5, 6}},
                                  {2016, new List<int> {2, 8, 9, 10}}
                              }
                  },
                  new A
                  {
                      Name = "a2",
                      Years = new Dictionary<int, List<int>>
                              {
                                  {2013, new List<int> {3, 4, 5, 6}},
                                  {2014, new List<int> {2, 8, 9, 10}}
                              }
                  },
                  new A
                  {
                      Name = "a3",
                      Years = new Dictionary<int, List<int>>
                              {
                                  {2015, new List<int> {3, 4, 5, 6}},
                                  {2014, new List<int> {2, 8, 9, 10}}
                              }
                  },
                  new A
                  {
                      Name = "a4",
                      Years = new Dictionary<int, List<int>>
                              {
                                  {2014, new List<int> {1, 4, 5, 6}},
                                  {2017, new List<int> {2, 8, 9, 10}}
                              }
                  }
              };

// listOfA is now {a1, a2, a3, a4}
listOfA = listOfA.OrderBy(a => a.Years.Min(y => y.Key + y.Value.Min() / 13d)).ToList();
// listOfA is now {a2, a4, a3, a1}

Upvotes: 1

Related Questions