Home > database >  How sort Dictionary by 2 criterias and subcriteria in c#
How sort Dictionary by 2 criterias and subcriteria in c#

Time:10-01

I want to sort myDictionary first by Key and then by Value.

Dictionary<int, double> myDictionary = new Dictionary<int, double>()
{
    {1,514},
    {2,509},
    {3,510},
    {4,509},
    {5,517},
    {6,512},
    {7,514},
    {8,511}
}

I need to find min and max Value, then to sort it by Key.

var orderedDict = myObjectDictionary
       .OrderByDescending(a => a.Value)
       .ThenBy(b => b.Key);

But I need to find this object with min Value farthest(using Key) from object with max Value. If there is two object with min/max Value to get farthest(using Key) one from opposite object(min/max).

After that I need to look for object near to min/max and if their Values are near to min/max Values and they are farthest to get them.

In this case: Max= 5, 517 Min= 3, 510

CodePudding user response:

Requirement: Can't get a min and a max if they are next to each other.

  • In the following solution I've assumed that myDictionary keys are incremented by 1.

You can have the desired output with the following code:

var groupedByValues = myDictionary.ToLookup(p => p.Value, p => p.Key);

var orderByValues = from item in groupedByValues
                    orderby item.Key ascending
                    select (Value:item.Key, Indexes: item.ToList());
var orderedByValues = orderByValues.ToList();

var maxCandidates = orderByValues.Last();
(int Key, double Value) max = (maxCandidates.Indexes.First(), maxCandidates.Value);
(int Key, double Value)? min = null;

foreach(var item in orderedByValues)
{
    if (item.Indexes.Any(idx => Math.Abs(idx - max.Key) == 1))
        continue;
    else
    {
        min = (item.Indexes.First(), item.Value);
        break;
    }
};

var groupedByValues = myDictionary.ToLookup(p => p.Value, p => p.Key);
  • Here we create groups based on the value, the groupedByValues looks like this:
514: 1,7
509: 2,4
510: 3
517: 5
512: 6
511: 8

var orderByValues = from item in groupedByValues
                    orderby item.Key ascending
                    select (Value:item.Key, Indexes: item.ToList());

var orderedByValues = orderByValues.ToList();
  • Here we simply order the previous collection by its keys
  • The orderByValues is just a query, the orderedByValues is its materialized form:
509: 2,4
510: 3
511: 8
512: 6
514: 1,7
517: 5

var maxCandidates = orderByValues.Last();
(int Key, double Value) max = (maxCandidates.Indexes.First(), maxCandidates.Value);
(int Key, double Value)? min = null;
  • By issuing the orderByValues.Last command we get the highest value
    • The highest value can be present multiple times that's why we have Indexes
    • I've picked the first index from Indexes but you might need to alter this logic based on your requirements
  • We convert the maxCandidates into the expected output format
  • We create a min variable, which is nullable to be able to initialize it

foreach(var item in orderedByValues)
{
    if (item.Indexes.Any(idx => Math.Abs(idx - max.Key) == 1))
        continue;
    else
    {
        min = (item.Indexes.First(), item.Value);
        break;
    }
};
  • Here we iterate through the orderedByValues collection in order to find the first min which satisfies all requirements
  • We are checking the distance between the max Key and the min candidate's indexes
    • If any of the indexes is next to the max key, then we continue searching
    • If none of the indexes is next to the max key, then we have found the min
  • Related