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
myDictionarykeys 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
groupedByValueslooks 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
orderByValuesis just a query, theorderedByValuesis 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.Lastcommand 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
Indexesbut you might need to alter this logic based on your requirements
- The highest value can be present multiple times that's why we have
- We convert the
maxCandidatesinto the expected output format - We create a
minvariable, 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
orderedByValuescollection in order to find the firstminwhich 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
