Reputation: 43
I have a Dictionary<string, float>
and want to select KeyValuePairs from that, where the difference between the float-values is smaller than a certain treshold.
This is the dictionary:
Dictionary<string, float> heights = new Dictionary<string, float> ();
sample entries:
"first", 61.456
"second", 80.567
"third", 62.456
"4", 59.988
"5", 90.34
"6", 82.123
i need those elements, with a small difference of their values, e.g. "first", "third" and "4" in a list or something similiar. the difference is a given float value, let's say 3.5
Is it possible to achieve that by Linq?
I tried to do this using loops, but it gets really messy somehow...
Upvotes: 4
Views: 648
Reputation: 13676
You can create custom method that look up for close values and accepts two parameters: dictionary that holds the values and float, that is used to hold the maximum lookup range :
static Dictionary<string, float> FindRange(Dictionary<string, float> dict, float precision)
{
Dictionary<string, float> temp = new Dictionary<string, float>();
List<int> counter = new int[dict.Count].ToList(); float[] values = dict.Values.ToArray();
for (int i = 0; i < values.Length; i++)
for (int i2 = 0; i2 < values.Length; i2++)
if (i2 != i && Math.Abs(values[i] - values[i2]) < precision) counter[i]++;
for (int i = 0; i < values.Length; i++)
if (Math.Abs(values[i] - values[counter.IndexOf(counter.Max())]) < precision)
temp.Add(dict.FirstOrDefault(kv => kv.Value == values[i]).Key, values[i]);
return temp;
}
Example of usage :
static void Main()
{
Dictionary<string, float> heights = new Dictionary<string, float>()
{
{"first", 61.456f},
{"second", 80.567f},
{"third", 62.456f},
{"4", 59.988f},
{"5", 90.34f},
{"6", 82.123f}
};
// returns max sequence of elements with difference less than 3f
var newDict = FindRange(heights, 3f);
foreach (var item in newDict)
{
Console.WriteLine(item.Key + " " + item.Value);
}
}
Output :
first 61,456
third 62,456
4 59,988
Upvotes: 1
Reputation: 2561
You can first sort the entries by value and then it will be easier to compare nearby entries.
var list = heights.ToList();
list.Sort((a,b) => {return a.Value.CompareTo(b.Value);});
bool first = true;
for (int i = 1; i < list.Count; ++i)
{
if (Math.Abs(list[i-1].Value - list[i].Value) < threshold)
{
if (first)
{
first = false;
Console.WriteLine(list[i-1]);
}
Console.WriteLine(list[i]);
}
}
A working example on dotnetfiddle here.
Upvotes: 1
Reputation: 7568
Something like:
List<KeyValuePair<string,float>> matching = new List<KeyValuePair<string,float>>();
int i = 0;
var all = _dict.Select(kvp => kvp).ToList().OrderBy(kvp => kvp.Value);
all.ForEach(kvp => {
if(i < all.Count() - 1 && Math.Abs(all[i+1].Value - kvp.Value) < threshhold)
{
matching.Add(kvp);
if(i == all.Count() - 1) matching.add(all[i+1]); // Need to manually add the final entry if it's a match
}
i++;
});
Upvotes: 0