PetrasVestartasEPFL
PetrasVestartasEPFL

Reputation: 576

SortedList using a string notation but sorted numerically

I noticed that sorted list of key int sorts values numerically

SortedList < int,double> sl0 = new SortedList<int,double>();
for(int i = 0; i < 20; i++)
  sl0.Add(i, 0.01);

[0, 0.01]
[1, 0.01]
[2, 0.01]
[3, 0.01]
[4, 0.01]
[5, 0.01]
[6, 0.01]
[7, 0.01]
[8, 0.01]
[9, 0.01]
[10, 0.01]
[11, 0.01]
[12, 0.01]
[13, 0.01]
[14, 0.01]
[15, 0.01]
[16, 0.01]
[17, 0.01]
[18, 0.01]
[19, 0.01]

and sorted list of key string sorts values alphabetically

SortedList < string,double> sl1 = new SortedList<string,double>();
for(int i = 0; i < 20; i++)
  sl1.Add(i.ToString(), 0.01);

[0, 0.01]
[1, 0.01]
[10, 0.01]
[11, 0.01]
[12, 0.01]
[13, 0.01]
[14, 0.01]
[15, 0.01]
[16, 0.01]
[17, 0.01]
[18, 0.01]
[19, 0.01]
[2, 0.01]
[3, 0.01]
[4, 0.01]
[5, 0.01]
[6, 0.01]
[7, 0.01]
[8, 0.01]
[9, 0.01]

Is there any way to have a nested key that would be sorted numerically for instance the order has to look like this for the keys. First I imagined that I can use strings like that, but for sure they are sorted alphabetically:

//Keys
//"0;0"
//"0;0;0"
//"0;1"
//"0;2"
//"0;10"
//"0;10;1;0;0"
//"1;0"
//"2;1"
//"3;1"
//"3;1;2"

For now I have a class that inherits sorted list:

public class Plates : Comparer<int[]> , IEnumerable<KeyValuePair<string, Plate>>{


    //Store all plates as a sorted list
    //String is use for storing groups
    //i.e. 0, 1, 2 ... fn
    //i.e. 0;0, 0;1, 0;2, 1;3, 1;4, 1;5 ... gn_fn
    private SortedList<string, Plate> sortedPlates;



    public Plates() {
        sortedPlates = new SortedList<string,Plate>();
    }

    #region IEnumerable Implementation
    public void Add(Plate item) => sortedPlates.Add(item.fID, item);
    public IEnumerator<KeyValuePair<string,Plate>> GetEnumerator() =>  sortedPlates.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    #endregion

    #region IComparer


    public override int Compare(int[] x, int[] y) {

        int[] a = x.Length < y.Length ? x : y;
        int[] b = x.Length < y.Length ? y : x;

        for(int i = 0; i < a.Length; i++) {
            if (a[i] != b[i])
                return a[i].CompareTo(b[i]);
        }

        return 0;

    }
    #endregion

Upvotes: 1

Views: 138

Answers (1)

Alexander Petrov
Alexander Petrov

Reputation: 14231

Custom comparer:

class KeyComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        var xs = x.Split(';');
        var ys = y.Split(';');

        int min = Math.Min(xs.Length, ys.Length);

        for (int i = 0; i < min; i++)
        {
            int cmp = xs[i].CompareTo(ys[i]);

            if (cmp != 0)
                return cmp;
        }

        return xs.Length.CompareTo(ys.Length);
    }
}

Using:

var list = new SortedList<string, double>(new KeyComparer());

list.Add("0;1", 0);
list.Add("0;0;0", 0);
list.Add("0;10;1;0;0", 0);
list.Add("0;2", 0);
list.Add("0;10", 0);
list.Add("1;0", 0);
list.Add("3;1;2", 0);
list.Add("2;1", 0);
list.Add("3;1", 0);
list.Add("0;0", 0);

foreach (var x in list)
    Console.WriteLine(x);

Upvotes: 2

Related Questions