Concurrent Dictionary AddOrUpdate method 3rd parameter? - c#

private readonly ConcurrentDictionary<string, System.Drawing.Color> _colorSet;
public void BuildColorSet(IList<string> colorNames, string prefix, bool forceLastToGray)
{
var size = forceLastToGray ? colorNames.Count - 1 : colorNames.Count;
int nbHue = 6;
int nbCycle = (int)Math.Ceiling((double)size / nbHue);
var saturationMax = nbCycle <= 2 ? 1.0 : 1.0;
var saturationMin = 0.3;
var luminanceMax = nbCycle <= 2 ? 0.85 : 0.85;
var luminanceMin = 0.3;
var maxSaturationShift = 0.30;
var maxLuminanceShift = 0.15;
var interval = 1.0 / Math.Min(size, nbHue);
var saturationShift = (saturationMax - saturationMin) / (nbCycle - 1);
saturationShift = Math.Min(saturationShift, maxSaturationShift);
var luminanceShift = (luminanceMax - luminanceMin) / (nbCycle - 1);
luminanceShift = Math.Min(luminanceShift, maxLuminanceShift);
var hueShift = 0.0;
var saturation = saturationMax;
var luminance = luminanceMax;
for(var i = 0; i<size; i++)
{
if(i > 0 && (i % nbHue == 0)) // Next Cycle
{
saturation -= saturationShift;
luminance -= luminanceShift;
hueShift = hueShift == 0 ? interval/2 : 0;
}
var hue = interval*(i%nbHue) + hueShift;
System.Drawing.Color color = HSL2RGB(hue, saturation, luminance);
_colorSet.AddOrUpdate(prefix + colorNames[i], color, ???);
}
if(forceLastToGray)
{
_colorSet.TryAdd(prefix + colorNames[colorNames.Count - 1], System.Drawing.Color.LightGray);
}
_cssDirty = true;
}
I want to be able to update the dictionary if the color exists with new value. And also add to dictionary if the color is not there in dictionary.
I am using the AddOrUpdate but not able to get the 3rd parameter(form the lambda expression OR delegate method) of the AddOrUpdate method.
Any idea how my 3rd parameter would look like?

From the documentation:
updateValueFactory
Type: System.Func
The function used to generate a new value for an existing key based on the key's existing value
This will leave the value in the collection alone if it already exists:
_colorSet.AddOrUpdate(prefix + colorNames[i], color,
(key, existingVal) =>
{
return existingVal;
});
This will replace the value in the collection with the same one specified for the insert:
_colorSet.AddOrUpdate(prefix + colorNames[i], color,
(key, existingVal) =>
{
return color;
});
You can perform conditional logic, comparisons between the old value and new value, or update the original object in the function, for example.
_colorSet.AddOrUpdate(prefix + colorNames[i], color,
(key, existingVal) =>
{
if (existingVal.Name == "Red")
return existingVal;
else
return color;
});

As per the web page asawyer gave you, what's required is a function
Func<TKey, TValue, TValue>
In this case it looks like you are passing a string and a Color but how you want to combing them is largely upto you. You need a function that returns a Color so the following should work from a syntax perspective.
(key, oldValue) => oldValue
I've no idea who you might calculating the new value. You could for example use your new color
_colorSet.AddOrUpdate(prefix + colorNames[i], color, (key, oldValue) => color);

It looks like you don't care if the color is already there; you always want to update the value in the dictionary. In that case you're better off using the normal indexer, e.g.
_colorSet[prefix + colorNames[i]] = color;

Related

How can i get the highest integer from a list string

I have a video clip which contains a bunch of Meta data (Mostly single line of strings), which in turn are linked to a specific frame. I managed to separate the speed data from each line of the Meta data and store it with in another list lc4_highest_speed_2
for (int h = 0; h < lc4_file_calculations.Count; h++)
{
string hold_variable = lc4_file_calculations[h].Replace("-", ",");
var mySplitResult2 = hold_variable.Split(',');
var speed = mySplitResult2[mySplitResult2.Length - 45];
lc4_highest_speed.Add(speed + ":" + h);
}
for (int f = 0; f < lc4_highest_speed.Count; f++)
{
string hoe3 = lc4_highest_speed[f];
var mySplitResult3 = hoe3.Split(':');
var speed2 = mySplitResult3[mySplitResult3.Length - 2];
var speed3 = mySplitResult3[mySplitResult3.Length - 1];
string speed_test = speed2.ToString();
lc4_highest_speed_2.Add(speed2 + " - " + speed3);
}
The new list holds data like this 012 - 82 the first part before the - is the speed and the other is the index number related to value from another string. I have tried things like concat, however it hasn’t worked. What would be the best way to get the highest speed the element before the - while also keeping the relation of the index number the number after the -.
Thank you
Try following :
string[] input = {
"012 - 82",
"012 - 83",
"012 - 84",
"012 - 85",
"012 - 86",
"012 - 87",
"13 - 102",
"13 - 103",
"13 - 104",
"13 - 105",
"13 - 106"
};
var output = input
.Select(x => x.Split(new char[] { '-' }))
.Select(x => new { speed = int.Parse(x.First()), index = int.Parse(x.Last()) })
.OrderByDescending(x => x.speed)
.GroupBy(x => x.speed)
.First()
.ToList();
A solution in O(n) time complexity return the higher speed value with its high index value.
int highestSpeed = 0;
int indexNumber = 0;
foreach (var item in lc4_highest_speed_2)
{
var values = item.Split('-');
if (values?.Count() == 2)
{
int.TryParse(values[0], out int parsedValue);
if (parsedValue > highestSpeed)
{
highestSpeed = parsedValue;
int.TryParse(values[1], out indexNumber);
continue;
}
int.TryParse(values[1], out int parsedIndex);
if (highestSpeed == parsedValue && parsedIndex > indexNumber) indexNumber = parsedIndex;
}
}
You can leverage a tuple to do this. Tuples automatically define an ordering based on their members that implement IComparable<T>. (Comparison is done in the order that the tuple's members are declared.)
Since an int implements IComparable<T> if we construct a tuple with the first element being the integer speed and the second the integer index, then the comparison operation generated for the tuple will be exactly what you need.
Thus you can solve this with a Linq expression that splits each row into the speed and index strings, parses those strings into ints and creates a tuple for each pair of speed and index. Then you can find the biggest using IEnumerable.Max():
var max = lc4_highest_speed_2.Select(item =>
{
var elements = item.Split("-");
return (speed: int.Parse(elements[0].Trim()), index: int.Parse(elements[1].Trim()));
}).Max();
Note that max is a tuple with an int first element called speed and an int second element called index.
Try it on .Net Fiddle
You can store all the speed value in the list of integer where you can find the mx value and using its index you then can find the relation between the speed and index value.
For the reference, I have created the small program. Hope you will understand
using System;
using System.Collections.Generic;
using System.Linq;
class HelloWorld {
static void Main() {
List<string> data = new List<string>();
List<int> intdata = new List<int>();
data.Add("012 - 82");
data.Add("013 - 102");
for(int i=0;i<data.Count;i++){
intdata.Add(Int16.Parse(data[i].Substring(0,data[i].IndexOf("-"))));
}
Console.WriteLine(intdata.Max());
}
}
Another way to do it:
var maxSpeed = lc4.Max(x => Convert.ToInt32(x.Split(' ')[0]));
var maxLine = lc4.FirstOrDefault(x => x.StartsWith($"{maxSpeed} "));
var maxIndex = Convert.ToInt32(maxLine.Split('-')[1].Substring(1));
or if you want all indices:
var maxSpeed = lc4.Max(x => Convert.ToInt32(x.Split(' ')[0]));
var maxLines = lc4.Where(x => x.StartsWith($"{maxSpeed} "));
var maxIndexes = maxLines.Select(x => Convert.ToInt32(x.Split('-')[1].Substring(1)));

How to add conditional inside Linq Aggregate in C#?

I'm trying Linq over Imperative style, but I can't convert this conditional inside Aggregate to Linq.
Consider two following examples.
Simple example:
public enum Color {
Red, // Red score = 10
Yellow, // Yellow score = 5
Green, // Green score = 2
}
//Populate our sample list
public List<Color> Colors = new List<Color> {Red, Green, Green, Yellow};
//I need help on this one
public float Score => Colors.Aggregate(0.0f, (total, next) =>
{
//How to properly use conditional inside Aggregate?
if (next == Color.Red) {
return total + 10.0f;
} else if (next == Color.Yellow) {
return total + 5.0f;
} else if (next == Color.Green) {
return total + 2.0f;
}
//edit: forgot the default
return total;
}
Log(Score); //19
Edit: I have tried moving the conditional to Select, but then it will just move the problem, Which is how to add conditional inside Linq Select?
public float Score => Colors.Select(x =>
{
// The problem still happening
if (x == Color.Red) {
return 10.0f;
} else if (x == Color.Yellow) {
return 5.0f;
} else if (x == Color.Green) {
return 2.0f;
}
return 0.0f;
}
.Aggregate(0.0f, (total, next) => total + next);
And here is the complex example, basically it's just a stat modifier for a game,
// This is a Game Status Modifier, for example: "Strength 30 + 10%"
public enum StatModType
{
Flat = 100, // Flat addition to Stat
PercentAdd = 200, // Percent addition to Stat
... // many other type of addition
}
private float _baseValue = 30.0f;
public List<StatModifier> StatModifiers = new List<StatModifier>
{...} //dummy data
public float Value => StatModifiers.Aggregate(_baseValue, (finalValue, mod) =>
{
//I need help on this one
if (mod.Type == StatModType.Flat)
return finalValue + mod.Value;
else if (mod.Type == StatModType.PercentAdd)
// When we encounter a "PercentAdd" modifier
return finalValue + finalValue * mod.Value;
else if (mod.Type == ...)
//and continues below everytime I add more modifier types..
}
Log(Value); // Strength = 33;
Edit: I'll just post (Credit: https://forum.unity.com/threads/tutorial-character-stats-aka-attributes-system.504095/) the imperative code in case someone needs it, I also have a hard time reading this one:
private float CalculateFinalValue()
{
float finalValue = BaseValue;
float sumPercentAdd = 0; // This will hold the sum of our "PercentAdd" modifiers
for (int i = 0; i < statModifiers.Count; i++)
{
StatModifier mod = statModifiers[i];
if (mod.Type == StatModType.Flat)
{
finalValue += mod.Value;
}
else if (mod.Type == StatModType.PercentAdd) // When we encounter a "PercentAdd" modifier
{
sumPercentAdd += mod.Value; // Start adding together all modifiers of this type
// If we're at the end of the list OR the next modifer isn't of this type
if (i + 1 >= statModifiers.Count || statModifiers[i + 1].Type != StatModType.PercentAdd)
{
finalValue *= 1 + sumPercentAdd; // Multiply the sum with the "finalValue", like we do for "PercentMult" modifiers
sumPercentAdd = 0; // Reset the sum back to 0
}
}
else if (mod.Type == StatModType.PercentMult) // Percent renamed to PercentMult
{
finalValue *= 1 + mod.Value;
}
}
return (float)Math.Round(finalValue, 4);
}
How can I add conditional inside Aggregate / Reduce / Scan function?
I suggest extracting model in both cases i.e.
Simple Example:
private static Dictionary<Color, float> s_ColorScores = new Dictionary<Color, float>() {
{Color.Red, 10.0f},
{Color.Yellow, 5.0f},
{Color.Green, 2.0f},
};
...
float Score = Colors
.Sum(color => s_ColorScores[color]);
Complex Example:
private static Dictionary<StatModType, Func<float, float, float>> s_Modifications = new
Dictionary<StatModType, Func<float, float, float>> {
{StatModType.Flat, (prior, value) => prior + value},
{StatModType.PercentAdd, (prior, value) => prior + prior * value},
//TODO: add modification rules here
};
public float Value => StatModifiers
.Aggregate(_baseValue, (prior, mod) => s_Modifications[mod.Type](prior, mod.Value));
So you are going to have game's model (s_ColorScores, s_Modifications...) with rules, settings, balances etc. (which you will probably want to tune, may be Color.Yellow score of 6.0f is a better choice) separated from simple business logics.
Assuming that the behaviors associated to the enum types are static and not dynamic, based on this MSDocs article another approach would be to use enumeration classes instead of enum types. To simplify this, you could use the SmartEnum package.
Using this lib and approach, your use cases turn into:
Simple Example:
public sealed class Color: SmartEnum<Color>
{
public static readonly Color Red = new Color (nameof(Red), 1, 10.0f);
public static readonly Color Yellow = new Color (nameof(Yellow), 2, 20.0f);
public static readonly Color Green = new Color (nameof(Green), 3, 30.0f);
private Color(string name, int value, double score)
: base(name, value)
{
this.Score = score;
}
public float Score {get;}
}
float TotalScore = Colors
.Sum(color => color.Score);
Complex Example:
public sealed class StatMod: SmartEnum<StatMod>
{
public static readonly StatMod FlatAdd = new StatMod(nameof(FlatAdd), 200, (prev, val)=>prev+val);
public static readonly StatMod PercentAdd = new StatMod(nameof(PercentAdd), 300, (prev,val)=>prior + prior * value);
private StatMod(string name, int value, Func<float, float, float> reduce) : base(name, value)
{
this.Reduce = reduce;
}
public Func<float, float, float> Reduce {get;}
}
public float Value => StatModifiers
.Aggregate(_baseValue, (prior, mod) => mod.Reduce(prev, mod.Value));

What's a good algorithm for checking if a given list of values alternates up and down?

Assuming the function takes in a list of double and an index to perform the check from, I need to check if the values alternates up and down consecutively.
For example, a list of [14.0,12.3,13.0,11.4] alternates consecutively but a list of [14.0,12.3,11.4,13.0] doesn't.
The algorithm doesn't have to be fast, but I'd like it to be compact to write (LINQ is totally fine). This is my current method, and it looks way too crude to my taste:
enum AlternatingDirection { Rise, Fall, None };
public bool CheckConsecutiveAlternation(List<double> dataList, int currDataIndex)
{
/*
* Result True : Fail
* Result False : Pass
*/
if (!_continuousRiseFallCheckBool)
return false;
if (dataList.Count < _continuousRiseFallValue)
return false;
if (currDataIndex + 1 < _continuousRiseFallValue)
return false;
AlternatingDirection direction = AlternatingDirection.None;
int startIndex = currDataIndex - _continuousRiseFallValue + 1;
double prevVal = 0;
for (int i = startIndex; i <= currDataIndex; i++)
{
if (i == startIndex)
{
prevVal = dataList[i];
continue;
}
if (prevVal > dataList[i])
{
prevVal = dataList[i];
switch (direction)
{
case AlternatingDirection.None:
direction = AlternatingDirection.Fall;
continue;
case AlternatingDirection.Rise:
direction = AlternatingDirection.Fall;
continue;
default:
//Two falls in a row. Not a signal.
return false;
}
}
if (prevVal < dataList[i])
{
prevVal = dataList[i];
switch (direction)
{
case AlternatingDirection.None:
direction = AlternatingDirection.Rise;
continue;
case AlternatingDirection.Fall:
direction = AlternatingDirection.Rise;
continue;
default:
//Two rise in a row. Not a signal.
return false;
}
}
return false;
}
//Alternated n times until here. Data is out of control.
return true;
}
Try this:
public static bool IsAlternating(double[] data)
{
var d = GetDerivative(data);
var signs = d.Select(val => Math.Sign(val));
bool isAlternating =
signs.Zip(signs.Skip(1), (a, b) => a != b).All(isAlt => isAlt);
return isAlternating;
}
private static IEnumerable<double> GetDerivative(double[] data)
{
var d = data.Zip(data.Skip(1), (a, b) => b - a);
return d;
}
Live demo
The idea is:
If the given list of values is alternating up and down, mathematically it means that it's derivative keeps changing its sign.
So this is exactly what this piece of code does:
Get the derivative.
Checks for sign fluctuations.
And the bonus is that it will not evaluate all of the derivative / signs arrays unless it is necessary.
I'd do it with a couple of consecutive zips, bundled in an extension method:
public static class AlternatingExtensions {
public static bool IsAlternating<T>(this IList<T> list) where T : IComparable<T>
{
var diffSigns = list.Zip(list.Skip(1), (a,b) => b.CompareTo(a));
var signChanges = diffSigns.Zip(diffSigns.Skip(1), (a,b) => a * b < 0);
return signChanges.All(s => s);
}
}
Edit: for completeness, here's how you'd use the feature:
var alternatingList = new List<double> { 14.0, 12.3, 13.0, 11.4 };
var nonAlternatingList = new List<double> { 14.0, 12.3, 11.4, 13.0 };
alternatingList.IsAlternating(); // true
nonAlternatingList.IsAlternating(); // false
I also changed the implementation to work on more types, making use of generics as much as possible.
Here is a small pseudo code. Assuming no repeated elements (can be handled easily though by few tweaks)
Idea is to have a sign variable which is alternating 1,-1,... that is multipled by the difference of two consecutive pairs, the difference multipled by this sign variable must always be positive. If it's not at some point, return false.
isUpAndDown(l):
if size(l) < 2: // empty,singleton list is always good.
return true
int sign = (l[0] < l[1] ? 1 : -1)
for i from 0 to n-1 (exclusive):
if sign * (l[i+1] - l[i]) < 0:
return false //not alternating
sign = sign * -1
end for
return true //all good
You may create kind of a signed array first:
double previous = 0;
var sign = myList.Select(x => {
int s = Math.Sign(x - previous);
previos = x;
return s;
});
This gives you a list similar to
{ -1, 1, -1, ... }
Now you can take a similar appraoch as the previos Select-statement to check if a -1 follows a 1:
var result = sign.All(x => {
bool b = x == -previous;
previous = x;
return b;
});
Now result is true if your list alternates, false otherwise.
EDIT: To ensure that the very first check within the second query also passes add previous = -sign[0]; before the second query.
Assuming that two equal values in a row are not acceptable (if they are, just skip over equal values):
if (dataList[0] == dataList[1])
return false;
bool nextMustRise = dataList[0] > dataList[1];
for (int i = 2; i < dataList.Count; i++) {
if (dataList[i - 1] == dataList[i] || (dataList[i - 1] < dataList[i]) != nextMustRise)
return false;
nextMustRise = !nextMustRise;
}
return true;
public double RatioOfAlternations(double[] dataList)
{
double Alternating = 0;
double Total = (dataList.Count()-2);
for (int (i) = 0; (i) < Total; (i)++)
{
if (((dataList[i+1]-dataList[i])*(dataList[i+2]-dataList[i+1]))<0)
// If previous change is opposite sign to current change, this will be negative
{
Alternating++;
}
else
{
}
}
return (Alternating/Total);
}

What's an Efficient Inversion of the Convert-to-Arbitrary-Base C# Function?

I need to convert an integer into a base64-character representation. I'm using OxA3's answer on this thread: Quickest way to convert a base 10 number to any base in .NET?
How do I inverse this to get my original integer back, given a string?
Joel Mueller's answer should guide you the base-64 case.
In response to the preliminary code you've provided in your own answer, you can definitely improve its efficiency by changing the code to accomplish what your for loop is doing (effectively an O(N) IndexOf) to use a hash lookup (which should make it O(1)).
I am basing this on the assumption that baseChars is a field that you initialize in your class's constructor. If this is correct, make the following adjustment:
private Dictionary<char, int> baseChars;
// I don't know what your class is called.
public MultipleBaseNumberFormatter(IEnumerable<char> baseCharacters)
{
// check for baseCharacters != null and Count > 0
baseChars = baseCharacters
.Select((c, i) => new { Value = c, Index = i })
.ToDictionary(x => x.Value, x => x.Index);
}
Then in your StringToInt method:
char next = encodedString[currentChar];
// No enumerating -- we've gone from O(N) to O(1)!
if (!characterIndices.TryGetValue(next, out nextCharIndex))
{
throw new ArgumentException("Input includes illegal characters.");
}
I have a first-pass of a working version here, albeit I'm not sure how efficient it is.
public static int StringToInt(string encodedString, char[] baseChars)
{
int result = 0;
int sourceBase = baseChars.Length;
int nextCharIndex = 0;
for (int currentChar = encodedString.Length - 1; currentChar >= 0; currentChar--)
{
char next = encodedString[currentChar];
// For loop gets us: baseChar.IndexOf(char) => int
for (nextCharIndex = 0; nextCharIndex < baseChars.Length; nextCharIndex++)
{
if (baseChars[nextCharIndex] == next)
{
break;
}
}
// For character N (from the end of the string), we multiply our value
// by 64^N. eg. if we have "CE" in hex, F = 16 * 13.
result += (int)Math.Pow(baseChars.Length, encodedString.Length - 1 - currentChar) * nextCharIndex;
}
return result;
}
Here is a version using Linq functionality and .NET Framework 4.0 Zip extension to perform the calculation.
public static int StringToInt(string encodedString, char[] baseChars) {
int sourceBase = baseChars.Length;
var dict = baseChars
.Select((c, i) => new { Value = c, Index = i })
.ToDictionary(x => x.Value, x => x.Index);
return encodedString.ToCharArray()
// Get a list of positional weights in descending order, calcuate value of weighted position
.Zip(Enumerable.Range(0,encodedString.Length).Reverse(), (f,s) => dict[f] * (int)Math.Pow(sourceBase,s))
.Sum();
}
FYI, calculating the dictionary once outside the function would be more efficient for a large batch of transformations.
Here's a complete solution that converts a base10 number to baseK and back:
public class Program
{
public static void Main()
{
int i = 100;
Console.WriteLine("Int: " + i);
// Default base definition. By moving chars around in this string, we can further prevent
// users from guessing identifiers.
var baseDefinition = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//var baseDefinition = "WBUR17GHO8FLZIA059M4TESD2VCNQKXPJ63Y"; // scrambled to minimize guessability
// Convert base10 to baseK
var newId = ConvertToBaseK(i, baseDefinition);
Console.WriteLine(string.Format("To base{0} (short): {1}", baseDefinition.Length, newId));
// Convert baseK to base10
var convertedInt2 = ConvertToBase10(newId, baseDefinition);
Console.WriteLine(string.Format("Converted back: {0}", convertedInt2));
}
public static string ConvertToBaseK(int val, string baseDef)
{
string result = string.Empty;
int targetBase = baseDef.Length;
do
{
result = baseDef[val % targetBase] + result;
val = val / targetBase;
}
while (val > 0);
return result;
}
public static int ConvertToBase10(string str, string baseDef)
{
double result = 0;
for (int idx = 0; idx < str.Length; idx++)
{
var idxOfChar = baseDef.IndexOf(str[idx]);
result += idxOfChar * System.Math.Pow(baseDef.Length, (str.Length-1) - idx);
}
return (int)result;
}
}
If base-64 is really what you need rather than "any base" then everything you need is already built in to the framework:
int orig = 1337;
byte[] origBytes = BitConverter.GetBytes(orig);
string encoded = Convert.ToBase64String(origBytes);
byte[] decoded = Convert.FromBase64String(encoded);
int converted = BitConverter.ToInt32(decoded, 0);
System.Diagnostics.Debug.Assert(orig == converted);

Good way to get the key of the highest value of a Dictionary in C#

I'm trying to get the key of the maximum value in the Dictionary<string, double> results.
This is what I have so far:
double max = results.Max(kvp => kvp.Value);
return results.Where(kvp => kvp.Value == max).Select(kvp => kvp.Key).First();
However, since this seems a little inefficient, I was wondering whether there was a better way to do this.
edit: .NET 6 introduced a new method
var max = results.MaxBy(kvp => kvp.Value).Key;
You should probably use that if you can.
I think this is the most readable O(n) answer using standard LINQ.
var max = results.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
edit: explanation for CoffeeAddict
Aggregate is the LINQ name for the commonly known functional concept Fold
It loops over each element of the set and applies whatever function you provide.
Here, the function I provide is a comparison function that returns the bigger value.
While looping, Aggregate remembers the return result from the last time it called my function. It feeds this into my comparison function as variable l. The variable r is the currently selected element.
So after aggregate has looped over the entire set, it returns the result from the very last time it called my comparison function. Then I read the .Key member from it because I know it's a dictionary entry
Here is a different way to look at it [I don't guarantee that this compiles ;) ]
var l = results[0];
for(int i=1; i<results.Count(); ++i)
{
var r = results[i];
if(r.Value > l.Value)
l = r;
}
var max = l.Key;
After reading various suggestions, I decided to benchmark them and share the results.
The code tested:
// TEST 1
for (int i = 0; i < 999999; i++)
{
KeyValuePair<GameMove, int> bestMove1 = possibleMoves.First();
foreach (KeyValuePair<GameMove, int> move in possibleMoves)
{
if (move.Value > bestMove1.Value) bestMove1 = move;
}
}
// TEST 2
for (int i = 0; i < 999999; i++)
{
KeyValuePair<GameMove, int> bestMove2 = possibleMoves.Aggregate((a, b) => a.Value > b.Value ? a : b);
}
// TEST 3
for (int i = 0; i < 999999; i++)
{
KeyValuePair<GameMove, int> bestMove3 = (from move in possibleMoves orderby move.Value descending select move).First();
}
// TEST 4
for (int i = 0; i < 999999; i++)
{
KeyValuePair<GameMove, int> bestMove4 = possibleMoves.OrderByDescending(entry => entry.Value).First();
}
The results:
Average Seconds Test 1 = 2.6
Average Seconds Test 2 = 4.4
Average Seconds Test 3 = 11.2
Average Seconds Test 4 = 11.2
This is just to give an idea of their relative performance.
If your optimizing 'foreach' is fastest, but LINQ is compact and flexible.
Maybe this isn't a good use for LINQ. I see 2 full scans of the dictionary using the LINQ solution (1 to get the max, then another to find the kvp to return the string.
You could do it in 1 pass with an "old fashioned" foreach:
KeyValuePair<string, double> max = new KeyValuePair<string, double>();
foreach (var kvp in results)
{
if (kvp.Value > max.Value)
max = kvp;
}
return max.Key;
You can sort dictionary by using OrderBy (for find min value) or OrderByDescending (for max value) then get first element. It also help when you need find second max/min element
Get dictionary key by max value:
double min = results.OrderByDescending(x => x.Value).First().Key;
Get dictionary key by min value:
double min = results.OrderBy(x => x.Value).First().Key;
Get dictionary key by second max value:
double min = results.OrderByDescending(x => x.Value).Skip(1).First().Key;
Get dictionary key by second min value:
double min = results.OrderBy(x => x.Value).Skip(1).First().Key;
This is a fast method. It is O(n), which is optimal. The only problem I see is that it iterates over the dictionary twice instead of just once.
You can do it iterating over the dictionary once by using MaxBy from morelinq.
results.MaxBy(kvp => kvp.Value).Key;
Little extension method:
public static KeyValuePair<K, V> GetMaxValuePair<K,V>(this Dictionary<K, V> source)
where V : IComparable
{
KeyValuePair<K, V> maxPair = source.First();
foreach (KeyValuePair<K, V> pair in source)
{
if (pair.Value.CompareTo(maxPair.Value) > 0)
maxPair = pair;
}
return maxPair;
}
Then:
int keyOfMax = myDictionary.GetMaxValuePair().Key;
Check These out:
result.Where(x=>x.Value==result.Values.Max()).Select(x=>x.Key).ToList()
My version based off the current Enumerable.Max implementation with an optional comparer:
public static TSource MaxValue<TSource, TConversionResult>(this IEnumerable<TSource> source, Func<TSource, TConversionResult> function, IComparer<TConversionResult> comparer = null)
{
comparer = comparer ?? Comparer<TConversionResult>.Default;
if (source == null) throw new ArgumentNullException(nameof(source));
TSource max = default;
TConversionResult maxFx = default;
if ( (object)maxFx == null) //nullable stuff
{
foreach (var x in source)
{
var fx = function(x);
if (fx == null || (maxFx != null && comparer.Compare(fx, maxFx) <= 0)) continue;
maxFx = fx;
max = x;
}
return max;
}
//valuetypes
var notFirst = false;
foreach (var x in source)
{
var fx = function(x);
if (notFirst)
{
if (comparer.Compare(fx, maxFx) <= 0) continue;
maxFx = fx;
max = x;
}
else
{
maxFx = fx;
max = x;
notFirst = true;
}
}
if (notFirst)
return max;
throw new InvalidOperationException("Sequence contains no elements");
}
Example usage:
class Wrapper
{
public int Value { get; set; }
}
[TestMethod]
public void TestMaxValue()
{
var dictionary = new Dictionary<string, Wrapper>();
for (var i = 0; i < 19; i++)
{
dictionary[$"s:{i}"] = new Wrapper{Value = (i % 10) * 10 } ;
}
var m = dictionary.Keys.MaxValue(x => dictionary[x].Value);
Assert.AreEqual(m, "s:9");
}
How about doing it in parallel using Interlocked.Exchange for thread safety :) Keep in mind that Interlocked.Exchange will only work with a reference type.(i.e. a struct or key value pair (unless wrapped in a class) will not work to hold the max value.
Here's an example from my own code:
//Parallel O(n) solution for finding max kvp in a dictionary...
ClassificationResult maxValue = new ClassificationResult(-1,-1,double.MinValue);
Parallel.ForEach(pTotals, pTotal =>
{
if(pTotal.Value > maxValue.score)
{
Interlocked.Exchange(ref maxValue, new
ClassificationResult(mhSet.sequenceId,pTotal.Key,pTotal.Value));
}
});
EDIT (Updated code to avoid possible race condition above):
Here's a more robust pattern which also shows selecting a min value in parallel. I think this addresses the concerns mentioned in the comments below regarding a possible race condition:
int minVal = int.MaxValue;
Parallel.ForEach(dictionary.Values, curVal =>
{
int oldVal = Volatile.Read(ref minVal);
//val can equal anything but the oldVal
int val = ~oldVal;
//Keep trying the atomic update until we are sure that either:
//1. CompareExchange successfully changed the value.
//2. Another thread has updated minVal with a smaller number than curVal.
// (in the case of #2, the update is no longer needed)
while (oldval > curVal && oldval != val)
{
val = oldval;
oldval = Interlocked.CompareExchange(ref minVal, curVal, oldval);
}
});
I think using the standard LINQ Libraries this is as fast as you can go.

Categories

Resources