jnm
jnm

Reputation: 41

sort a dictionary's keys based on its values; values represent arrays and sorting order varies - ascending/descending; c#

I would like to sort a list of objects. The structure is a Dictionary<object, double[]> and looks like this:

    Dictionary<int, double[]> dict = new Dictionary<int, double[]>{
    {object1, new double[]{0.02, 0.10, 0.30, 0.5}},
    {object4, new double[]{0.02, 0.10, 0.30, 0.2}},
    {object3, new double[]{0.02, 0.10, 0.30, 0.3}},
    {object2, new double[]{0.02, 0.10, 0.50, 0.4}}
    };

The arrays should be ordered in different orders based on the index. i.e ascending for the 1st, 2nd and 4th index and descending for the 3rd index. So eventually, I should get:

object2, 0.02, 0.1, 0.5, 0.4
object4, 0.02, 0.1, 0.3, 0.2
object3, 0.02, 0.1, 0.3, 0.3
object1, 0.02, 0.1, 0.3, 0.5

I 'm using the code posted here as a starting point. What kind of adjustments should I make? Of course I understand that the method will not be generic (array length unrelated) anymore. I was considering creating a bool[] which has the same size as the double[], where True stands for ascending sorting and False for descending, but Compare method strictly gets 2 arguments. Any help would be much appreciated. Thanks!

Upvotes: 0

Views: 112

Answers (2)

Yaroslav Bres
Yaroslav Bres

Reputation: 1317

If I got you correctly, just try to use this comparer:

    public class SequenceComparer : IComparer<IList<double>>
    {
        public SequenceComparer(bool[] markers)
        {
            Markers = markers;
        }

        public bool[] Markers { get; }
        
        public int Compare(IList<double> x, IList<double> y)
        {
            //check for null
            if (x == null || y == null || Markers == null)
            {
                throw new Exception("Null arrays are not valid");
            }

            //check identical count
            if (x.Count != y.Count || x.Count != Markers.Length)
            {
                throw new Exception("Invalid count");
            }

            for (var i = 0; i < x.Count; i++)
            {
                if (x[i].Equals(y[i]))
                {
                   continue;
                }

                var comparisonResult = x[i] > y[i] ? 1 : -1;
                
                //if marker is false, invert comparisonResult
                return Markers[i] ? comparisonResult : comparisonResult * -1;
            }

            //Your arrays are identical, just skip
            return 1;
        }
    }

You can use any length arrays and regulate ordering direction with bool[] flags
Example of using:

var query = dict.OrderBy(pair => pair.Value, new SequenceComparer(new []{true, true, false, true}));

Upvotes: 1

Mike67
Mike67

Reputation: 11342

You can use the Linq library. Call OrderBy on the dictionary.

var x = dict.OrderBy(o => o.Value[0]).ThenBy(o => o.Value[1]).ThenBy(o => -o.Value[2]).ThenBy(o => o.Value[3]);

Full Code:

using System.Linq;
...........
public static void Main()
    {
        var object1 = 1;
        var object2 = 2;
        var object3 = 3;
        var object4 = 4;
        
        Dictionary<int, double[]> dict = new Dictionary<int, double[]>{
        {object1, new double[]{0.02, 0.10, 0.30, 0.5}},
        {object4, new double[]{0.02, 0.10, 0.30, 0.2}},
        {object3, new double[]{0.02, 0.10, 0.30, 0.3}},
        {object2, new double[]{0.02, 0.10, 0.50, 0.4}}
        };
        
        var x = dict.OrderBy(o => o.Value[0]).ThenBy(o => o.Value[1]).ThenBy(o => -o.Value[2]).ThenBy(o => o.Value[3]);
        
        // write ordered values
        foreach (var d in x)
        {
            Console.Write(d.Key + ", [");
            foreach (var v in d.Value)
                Console.Write(v + ", ");
            Console.WriteLine("]");
        }
    }

Output

2, [0.02, 0.1, 0.5, 0.4, ]
4, [0.02, 0.1, 0.3, 0.2, ]
3, [0.02, 0.1, 0.3, 0.3, ]
1, [0.02, 0.1, 0.3, 0.5, ]

Upvotes: 2

Related Questions