I have a List of KeyValuePairs
var hitCoord = new List<KeyValuePair<int, double>>()
and sorted like this (descending by Key)
hitCoord.Sort((a, b) => (b.Key.CompareTo(a.Key)));
I can find the total highest Value with
hitCoord.Sort((a, b) => (b.Value.CompareTo(a.Value)));
(^ maybe that can be used for the following query?)
I would like to partition the Keys in my list such that I can find Values that meet a condition within the specified range of keys.
i.e. I would like to find the highest Value and Lowest Value in a range of (int)Keys
for (i=0; i<hitCoord.Count; i++)
{
if (hitCoord[i].Key > (int lowerbound) && hitCoord[i].Key < (int upperBound)
{
find highest Value?
}
}
Not sure if that is at all on the right track. I am new to programming and very new to KeyValuePairs. Any help you can offer on this matter is much appreciated! Thank you!
Finding the max value in a specified range of keys could be solved by using LINQ (using System.Linq;) like this:
hitCoord.Where(c => c.Key > lowerbound && c.Key < upperbound).Max(c => c.Value);
The approach:
Use Where to filter all items with key in range
Use Max to get the max value
You could adapt and extend the query also with more checks and constraints. Some basic queries are described in Basic LINQ Query Operations (C#).
You don't need to actually sort - you can do this with Linq (adding using System.Linq; to the top of your .cs file). You just want a Where to filter by key and a Max to get the highest value:
var maxValue = hitCoord.Where(hc => hc.Key > lowerbound && hc.Key < upperBound)
.Max(hc => hc.Value);
As others have suggested this is all pretty easy to do with linq. here's another sample of linq calls including how to create a partition lookup.
var hitCoord = new List<KeyValuePair<int, double>>()
{
new KeyValuePair<int, double>(1, 1.1),
new KeyValuePair<int, double>(1, 1.2),
new KeyValuePair<int, double>(2, 2.0),
new KeyValuePair<int, double>(2, 2.1)
};
var partitions = hitCoord.ToLookup(kvp => kvp.Key % 2);
var maxKvp = hitCoord.Max(kvp => kvp.Key);
var minKvp = hitCoord.Min(kvp => kvp.Key);
int lower = 1;
int higher = 2;
var maxInRange = hitCoord.Where(kvp => kvp.Key >= lower && kvp.Key <= higher).Max(kvp => kvp.Key);
That said if this is perfromance critical then you'll probably want to use something other than linq so you can optimize it and avoid going through the list multiple times.
Related
I have a Dictionary, which has a hash table, that is, keys are not sorted.
Conflicts oConflicts = oClash.Conflicts;
Dictionary<string, string> dConflicts = new Dictionary<string, string>();
Conflict oConflict;
for (int iLoopC = 1; iLoopC <= oConflicts.Count; iLoopC++)
{
oConflict = oConflicts.Item(iLoopC);
if (Math.Abs(oConflict.Value) < 3)
{
dConflicts.Add(oConflict.Value.ToString(), oConflict.SecondProduct.ToString());
}
}
I have sorted the dictionary by LINQ:
var sortedDict = dConflicts.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
I am new to this. Could someone help me with how to get the value stored in sortedDict using the particular key value? Like the last value using count the array elements.
This seems that you are only using a Dictionary just to be sure not Adding duplicates, pretty overkill, but hey...
var searchedLastElement = dConflicts.OrderBy(x => x.Value).LastOrDefault().Value;
yod didn't need the sorted list to be cast again to dictionary only to retrieve the last element
For example i have a collection like this
var c1 = new Collection<int>{0,0,2,2,2,3,3,4,4,4,4,5,5,6,6,7};
I would like to get result like this
(6,5,4)
You can do:
c1.Distinct()
.OrderByDescending(x => x)
.Skip(1)
.Take(3)
.ToList()
First remove all the duplicates, then sort despondingly. Skip(1) so that the max element is removed. Finally you can take 3 elements from the rest.
In the old days, before LINQ, we might have done this on a sorted collection like you have:
var maxes = new int[4];
var idx = 0;
var max = 0;
foreach(var c in c1)
if(c > max)
max = maxes[(idx++)%4] = c;
At the end of this you'll have an array with 4 max values - the 3 you want, and the one you don't (which is in (idx - 1) % 4). I don't know if I'd use it now, but it's more efficient than a "distinct, then sort, then skip then take" approach as it does its work in a single pass
Here's the code i have:
Dictionary<double, long> dictionary = new Dictionary<double, long>();
dictionary.Add(99, 500);
dictionary.Add(98, 500);
dictionary.Add(101, 8000);
dictionary.Add(103, 6000);
dictionary.Add(104, 5);
dictionary.Add(105, 2000);
double price = 100;
the query i want is:
the key that is nearest price AND with the lowest value.
so in the above example it should return 99.
how do i code this in LINQ ?
i have seen alot of linq examples but i cannt adapt any of them to my needs b/c my query has 2 conditions.
thanks for any help.
edit:
based on comments from #nintendojunkie and #DmitryMartovoi i have had to rethink my approach.
if i prioritize key closest to price then resulting value may not be the lowest and if i prioritize value first then the key may be too far from price so the query will have to prioritize BOTH the key and value the same and give me the lowest value with the closest key to price. both key and value are equally important.
can anyone help on this?
thanks
Don't forget - you use dictionary. Dictionary has only unique keys. I think you consider this structure as List<KeyValuePair<double, long>>. If so - please look to this example:
var minimumKeyDifference = dictionary.Min(y => Math.Abs(y.Key - price));
var minimumItems = dictionary.Where(x => Math.Abs(x.Key - price).Equals(minimumKeyDifference));
var desiredKey = dictionary.First(x => x.Value.Equals(minimumItems.Where(y => y.Key.Equals(x.Key)).Min(y => y.Value))).Key;
You say that you need to find the closest price and the lowest value, but you don't define the rules for attributing precedence between two. In the below, I'm attributing them equal precedence: a price distance of 1 is equivalent to a value of 1.
var closest =
dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price) + kvp.Value).First();
The OrderBy(…).First() should be replaced by a MinBy(…) operator, if available, for performance.
Edit: If the value is only meant to serve as a tiebreaker, then use this (also posted by Giorgi Nakeuri):
var closest =
dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price))
.ThenBy(kvp => kvp.Value)
.First();
You can do it this way:
var result = dictionary.Select(c => new { c.Key, Diff = Math.Abs(price - c.Key) + Math.Abs(price - c.Value), c.Value }).OrderBy(c => c.Diff).FirstOrDefault();
The following works if you change your dictionary key's data type to decimal instead of double.
decimal price = 100;
decimal smallestDiff = dictionary.Keys.Min(n => Math.Abs(n - price));
var nearest = dictionary.Where(n => Math.Abs(n.Key - price) == smallestDiff)
.OrderBy(n => n.Value).First();
If you use double this may fail due to rounding issues, but decimal is preferred for anything having to do with money to avoid those issues.
var price = 100.0;
var nearestKey = (from pair in dictionary
let diff = Math.Abs(pair.Key - price)
select new {Key = pair.Key, Diff = diff}
order by diff desc).First().Key;
var minValue = dictionary[nearestKey];
Maybe you want a magic linq query but i suggest to try the in below.
public static class MyExtensions
{
public static double? GetNearestValue (this IDictionary<double, long> dictionary, double value)
{
if (dictionary == null || dictionary.Count == 0)
return null;
double? nearestDiffValue = null;
double? nearestValue = null;
foreach (var item in dictionary) {
double currentDiff = Math.Abs (item.Key - value);
if (nearestDiffValue == null || currentDiff < nearestDiffValue.Value) {
nearestDiffValue = currentDiff;
nearestValue = item.Value;
}
}
return nearestValue;
}
}
And call like this
Console.WriteLine (dictionary.GetNearestValue (100d));
var min = dictionary
.OrderBy(pair => pair.Value)
.Select(pair =>
new
{
k = pair.Key,
d = Math.Abs(pair.Key - price)
})
.OrderBy(t => t.d)
.Select(t => t.k)
.FirstOrDefault();
I'm teaching myself c# and working on my own mini project. The program populates an array with random numbers, the program returns the number (0-15) and the number of occurrences it appears in the array. I stored these values in a dictionary as I wanted to sort the values without losing the key mapped to it.
The sorted values are then stored into another dictionary and now I want to be able to iterate through the dictionary and get the key with the highest value. In other words print to the console the number with the most occurrences. As the dictionary is sorted, the last number will be the highest value.
However there could be more than one number tied for the most occurrences and that's where I'm stuck on. If the numbers 4,5,6,7 all appear the most number of times, i want to be able to print that to the console.
Dictionary<int, int> dic = new Dictionary<int, int>();
//iterates through numbers 0-15
for (int y = 0; y <= 15; y++)
{
int m = 0;
//iterates through entire array
for (int i = 0; i < Arr.Length; i++)
{
//comparisons
if (y == Arr[i])
{
m++;
}
}
//Inserts number and count into the dictionary
dic.Add(y,m);
}
//Sorts the dictionary and adds the sorted one into a new dictionary
Dictionary<int, int> dic2 = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> value in dic.OrderBy(key => key.Value))
{
Console.WriteLine("{0} appears {1} times ", value.Key, value.Value);
dic2.Add(value.Key, value.Value);
}
//Finds the keys with most common occurance
KeyValuePair<int, int> e = dic2.Last();
foreach (KeyValuePair<int, int> comp in dic2)
{
if (dic.Last() == dic[comp])
{
//something goes here
Console.WriteLine("Most common number is {0}", e.Key);
}
}
I'm not sure whether to use indexes to compare using the key or if there is another way to do this like I have tried above, using a foreach loop
I wouldn't use the current approach at all, to be honest - you're doing much more work than you need to. LINQ gives you much better tools than this. You can use GroupBy to make it all cleaner:
var pairs = array.GroupBy(x => x)
.Select(g => new { Key = g.Key, Count = g.Count() }
.OrderByDescending(pair => pair.Count)
.ToList();
That gets you all the key/count pairs, most-frequent first. The display part should then be reasonably simple, e.g.
// Note: this relies on the initial array being non-empty
var highestCount = pairs.First().Count;
foreach (var pair in pairs.TakeWhile(pair => pair.Count == highestCount))
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Count);
}
Just to be clear, the code above replaces all the code in your question. You don't need a Dictionary<,> at all.
You could use a linq query to find the number of ocurrencies for each key and count it. After, return a anon object with the Key and total, for sample:
var q = from k in dic
let t = dic.Count(x => x.Value == k.Key)
select new { Key = k.Key, Total = t };
var max = q.OrderByDescending(x => Total).First();
Console.WriteLine("Most common number is {0} with {1} ocurrencies", max.Key, max.Total);
Using a LINQ query (with C#) how would I go about do something like this (pseudocode)?
I'd look to do something like this is in places where, for example, I might generate 1000's of lists of 100's of random (bounded) integers, where I want to track the smallest of them as they're generated.
Best <- null value
Foreach N in Iterations
NewList <- List of 100 randomly generated numbers
If Best is null
Best <- NewList
If Sum(NewList) < Sum(Best)
Best <- NewList
Select Best
I've tried all sorts of things, but I can't really get it working. This isn't for any kind of project or work, just for my own curiosity!
Example of what I was thinking:
let R = new Random()
let Best = Enumerable.Range(0, 100).Select(S => R.Next(-100, 100)).ToArray()
//Where this from clause is acting like a for loop
from N in Iterations
let NewList = Enumerable.Range(0, 100).Select(S => R.Next(-100, 100))
Best = (NewList.Sum() < Best.Sum())? NewList : Best;
select Best
I believe you are looking for fold (aka "reduce") which is known as Aggregate in LINQ.
(IEnumerable.Min/Max are special-cases, but can be written in terms of fold/Aggregate.)
int Max (IEnumerable<int> x) {
return x.Aggregate(int.MinValue, (prev, cur) => prev > cur ? prev : cur);
}
Max(new int[] { 1, 42, 2, 3 }); // 42
Happy coding.
Looks like you're just selecting the minimum value.
var minimum = collection.Min( c => c );
You are effectively finding the minimum value in the collection, if it exists:
int? best = null;
if (collection != null && collection.Length > 0) best = collection.Min();