LINQ KeyValuePair List select value - c#

I am sure it has been answered somewhere before but for the love of god I cant find it.
I want to get a specific Value for a Key from a KeyValuePair List per LINQ one-liner.
My List: List<KeyValuePair<int, int>> LeagueKVPList
I think it goes something like this:
int x = LeagueKVPList.Where(v => v.Key.(int y)).Value
But that obviously does not work.
Thanks for any help.

You should use Select for that
var values = LeagueKVPList.Select(kvp => kvp.Value);
It returns you all values.
To get a single value you can use FirstOrDefault
var x = LeagueKVPList.FirstOrDefault(kvp => kvp.Key == y).Value;

Related

Better way then sorting dictionary and getting keys only

I have a dictionary of customers and associated data (e.g. MoneySpent) and would like to return the sorted list of customers only.
The only solution I figured out so far is this:
CustomerData<Customer, int> //the value here is the money spent
List<KeyValuePair<Customer, int>> sortedListByValue = CustomerData.OrderByDescending(s => s.Value).ToList();
Then just going throug the list and obtaining keys. However, I am sure there is an easier way of doing and would be glad for advice.
You can select the Key which will give you the customers.
var sortedListByValue = CustomerData.OrderByDescending(s => s.Value)
.Select(x => x.Key).ToList();

Making a list distinct in C#

In C#, I have an object type 'A' that contains a list of key value pairs.
The key value pairs is a category string and a value string.
To instantiate object type A, I would have to do the following:
List<KeyValuePair> keyValuePairs = new List<KeyValuePair>();
keyValuePairs.Add(new KeyValuePair<"Country", "U.S.A">());
keyValuePairs.Add(new KeyValuePair<"Name", "Mo">());
keyValuePairs.Add(new KeyValuePair<"Age", "33">());
A a = new A(keyValuePairs);
Eventually, I will have a List of A object types and I want to manipulate the list so that i only get unique values and I base it only on the country name. Therefore, I want the list to be reduced to only have ONE "Country", "U.S.A", even if it appears more than once.
I was looking into the linq Distinct, but it does not do what I want because it I can't define any parameters and because it doesn't seem to be able to catch two equivalent objects of type A. I know that I can override the "Equals" method, but it still doesn't solve the my problem, which is to render the list distinct based on ONE of the key value pairs.
To expand upon Karl Anderson's suggestion of using morelinq, if you're unable to (or don't want to) link to another dll for your project, I implemented this myself awhile ago:
public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> source, Func<T, U>selector)
{
var contained = new Dictionary<U, bool>();
foreach (var elem in source)
{
U selected = selector(elem);
bool has;
if (!contained.TryGetValue(selected, out has))
{
contained[selected] = true;
yield return elem;
}
}
}
Used as follows:
collection.DistinctBy(elem => elem.Property);
In versions of .NET that support it, you can use a HashSet<T> instead of a Dictionary<T, Bool>, since we don't really care what the value is so much as that it has already been hashed.
Check out the DistinctBy syntax in the morelinq project.
A a = new A(keyValuePairs);
a = a.DistinctBy(k => new { k.Key, k.Value }).ToList();
You need to select the distinct property first:
Because it's a list inside a list, you can use the SelectMany. The SelectMany will concat the results of subselections.
List<A> listOfA = new List<A>();
listOfA.SelectMany(a => a.KeyValuePairs
.Where(keyValue => keyValue.Key == "Country")
.Select(keyValue => keyValue.Value))
.Distinct();
This should be it. It will select all values where the key is "Country" and concat the lists. Final it will distinct the country's. Given that the property KeyValuePairs of the class A is at least a IEnumerable< KeyValuePair< string, string>>
var result = keyValuePairs.GroupBy(x => x.Key)
.SelectMany(g => g.Key == "Country" ? g.Distinct() : g);
You can use the groupby statement. From here you can do all kind off cool stuf
listOfA.GroupBy(i=>i.Value)
You can groupby the value and then sum all the keys or something other usefull

how to use linq to retrieve values from a 2 dimensional generic list

I have a generic List List[int, myClass], and I would like to find the smallest int value, and retrieve the items from the list that match this.
I am generating this from another LINQ statement
var traysWithExtraAisles = (from t in poolTrays
where t.TrayItems.Select(i=>i.Aisle)
.Any(a=> ! selectedAisles.Contains(a))
select new
{
count= t.TrayItems.Select(i=>i.Aisle)
.Count(a=> !selectedAisles.Contains(a)),
tray=t
}).ToList();
this gives me my anonymous List of [count, Tray], but now I want to figure out the smallest count, and return a sublist for all the counts that match this.
Can anyone help me out with this?
var smallestGroup = traysWithExtraAisles
.GroupBy(x => x.count)
.OrderBy(g => g.Key)
.First();
foreach(var x in smallestGroup)
{
var poolTray = x.tray;
}
You can use SelectMany to "flatten" your list. Meaning, combine all of the lists into one, then take the Min. So;
int minimum = poolTrays.SelectMany(x => x).Min(x => x.TheIntegerIWantMinOf);
Will give you the smallest value contained in the sub lists. I'm not entirely sure this is what you're asking for but if your goal is simply to find the smallest element in the collection then I would scrap the code you posted and use this instead.
Right, I now realise this is actually incredibly easy to do with a bit more fiddling around. I have gone with
int minCount = traysWithExtraAisles.Min(x=>x.count);
var minAislesList = (from t in trayswithExtraAisles
where t.count==mincount
select t).ToList()
I imagine it is probably possible to do this in one statement
You can use GroupBy as answered by Tim... or OrderBy as follow:
var result = traysWithExtraAisles.OrderBy(x=>x.count)
.TakeWhile((x,i)=> i == 0 || x.count == traysWithExtraAisles[i-1]).count;

C# remove duplicate dictionary items from List<>?

So I a collection of dictionary items in a list:
List<Dictionary<string, string>> inputData = new List<Dictionary<string, string>>(inputs);
List<Dictionary<string, string>> itemStack = new List<Dictionary<string, string>>();
Now what I want to do is for each inputData dictionary item I want to check if itemStack has the same value (Dictionary Item) already.
I was thinking it would be like?
foreach (var item in inputData)
{
if(!itemStack.Contains(item){ itemStack.Add(item)}
else{ //Duplicate found}
}
It doesn't really check the items values inside? It just assumes that it doesn't have it...
All i want is if itemStack contains and item that is already in the stack don't include it.
I know I'm missing something obvious.
Thanks,
Dictionary is reference type, so it doesn't check the "deep" value like you expected.
You will have to write your own "Contains" method, either as totally separate method or extension of the Dictionary itself then use it instead, for example:
if(!MyContains(itemStack, item)){ itemStack.Add(item)}
True that a HashSet would be better, but if you want to do it here, try this (assuming you are filtering duplicate keys only):
foreach (var item in inputData.Keys)
{
if (itemStack.Where(x => x.Key == item.Key).Count() > 0)
// There was a duplicate
}
Or, if you only care when the data is coming out you can call:
itemStack.Distinct()
I think, your way is right. On my mind, HashSet is good, but when you add a new element, it performs the same test on the contents of the same items.
Regards.
Based on your initial problem statement, you might do something like this:
var aggregateKnownKeys = itemStack.SelectMany(d => d.Keys);
itemStack.AddRange(
inputData.Select(d=> d.Where(p => !aggregateKnownKeys.Contains(p.Key))
.ToDictionary(p => p.Key, p => p.Value)));
If you only need to combine two dictionaries then you could do this to skip keys that exist in itemStack:
var inputData = new Dictionary<string, string>();
var itemStack = new Dictionary<string, string>();
var oldStack = itemStack;
itemStack = new[] { inputData.SkipWhile(d => oldStack.Keys.Contains(d.Key)), itemStack }
.SelectMany(d => d)
.ToDictionary(d => d.Key, d => d.Value);
Okay so this isn't quite a full answer but it's what I did.
So I have a List of items and instead of doing a full compare to whats in an List(Hence the other considered) I just did a single item check:
if(!String.IsNullOrEmpty(item["itemId"]))
{
alert.DaleksApproaching(item["itemId"]);
}
So when it does see it has a value it just does another event to get rid of it.
The idea of using LINQ and the method approaches about(Contains and Distinct)I like. I have yet to try that, but I plan on doing that. For this it doesn't use LINQ :(
Thanks everyone!

Inline Declaration Of Dictionary<> in C# with FOREACH()

Can anybody help out with the syntax of something like this:
Dictionary<string,string> dict = new Dictionary<string,string>()
{
foreach(var i in collection<Items>)
-----add i to dictionary
}
It's not really clear to me what you mean, but the ToDictionary LINQ extension method may help you. For example:
var dictionary = collection.ToDictionary(item => item.Key,
item => item.Value);
(Obviously you can vary how the key and value are obtained from the item.)
You can use LINQ for this:
Dictionary<string,string> dict = collection.ToDictionary(i => i.MyKey, i => i);
You can do something like UserCollection.ForEach(d => ...add each d.key and d.value to the dictionay and any other logic associated with selecting the key and value), assuming the collection of User types is in a List format or if it's an IEnumerable you can just do .ToList().ForEach(...

Categories

Resources