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, theorderedByValues
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
- The highest value can be present multiple times that's why we have
- 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 firstmin
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