Get single value from dictionary by key - c#

var listaFirme = new Dictionary<string, string>
{
{ "foo", "bar" }
};
var matchKey = "foo";
return listaFirme.Where(pair => pair.Key == matchKey).Select(pair => pair.Value).ToString();
I know that the keys are unique, so I want to return one value from my Dictionary. In this case it doesn't work, as it returns the string "System.IEnumerable<String>"...

It really does seem like you're overcomplicating this issue.
You can just use the indexer ([]) of the Dictionary class along with the .ContainsKey() method.
If you use something like this:
string value;
if (myDict.ContainsKey(key))
{
value = myDict[key];
}
else
{
Console.WriteLine("Key Not Present");
return;
}
You should achieve the effect that you want.

If you want to retrieve a value of a key from a dictionary access by indexer or TryGetValue:
var value = listaFirme[matchKey];
//If you don't know for sure that dictionary contains key
string value;
if(a.TryGetValue(matchKey, out value))
{
/* Code here */
}
As for why you got the result you did: Linq operations of Where and Select return an IEnumerable<T> so when doing ToString on it it executes the ToString of IEnumerable which is to print it's type.
Notice that listaFirme isn't a good name for a dictionary
If you did not have a dictionary and wanted to return one item then you'd use FirstOrDefault:
var value = someList.FirstOrDefault(item => /* some predicate */)?.Value;

It seems that you've overcomplicated the usage. In this case you don't need Linq.
Just use the Dictionary provided indexer: listaFirme[matchKey]. This returns the related value. IF the key does not exist the Dictionary throws a KeyNotFoundException exception. If you want to check if the key exists you can use the ContainsKey() method which returns a bool.

Replace toString(); with FirstOrDefault();
When you are applying .Where() condition it will return an Enumerable. You have to either cast it to list using .ToList() then you will get list of the values that meet the condition you used, or if you just want to get the first one you can use FirstOrDefault();
You can also write it like this
listaFirme.FirstOrDefault(pair => pair.Key == matchKey).Value
Since FirstOrDefault() accepts a predicate, you don't need always need to use .Where.

Related

Get last duplicate element in a list

I have a list contains duplicate items.
List<string> filterList = new List<string>()
{
"postpone", "access", "success", "postpone", "success"
};
I get the output which is postpone, access, success by using
List<string> filter = filterList.Distinct().ToList();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I had saw other example, they can use groupby to get the latest element since they have other item like ID etc. Now I only have the string, how can I get the latest item in the list which is access, postpone, success? Any suggestion?
One way to do this would be use the Index of the item in original collection along with GroupBy. For example,
var lastDistinct = filterList.Select((x,index)=> new {Value=x,Index=index})
.GroupBy(x=>x.Value)
.Select(x=> x.Last())
.OrderBy(x=>x.Index)
.Select(x=>x.Value);
var result = string.Join(",",lastDistinct);
Output
access,postpone,success
An OrderedDictionary does this. All you have to do is add your items to it with a logic of "if it's in the dictionary, remove it. add it". OrderedDictionary preserves the order of adding so by removing an earlier added one and re-adding it it jumps to the end of the dictionary
var d = new OrderedDictionary();
filterList.ForEach(x => { if(d.Contains(x)) d.Remove(x); d[x] = null; });
Your d.Keys is now a list of strings
access
postpone
success
OrderedDictionary is in the Collections.Specialized namespace
If you wanted the keys as a CSV, you can use Cast to turn them from object to string
var s = string.Join(",", d.Keys.Cast<string>());
Your input list is only of type string, so using groupBy doesn't really add anything. If you consider your code, your first line gives you the distinct list, you only lose the distinct items because you did a string.join on line 2. All you need to do is add a line before you join:
List<string> filter = filterList.Distinct().ToList();
string last = filter.LastOrDefault();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I suppose you could make your code more terse because you need neither .Select(a => a) nor .ToArray() in your call to string.Join.
GroupBy would be used if you had a list of class/struct/record/tuple items, where you might want to group by a specific key (or keys) rather than using Distinct() on the whole thing. GroupBy is very useful and you should learn that, and also the ToDictionary and ToLookup LINQ helper functionality.
So why shouldn't you return the first occurrence of "postpone"? Because later in the sequence you see the same word "postpone" again. Why would you return the first occurrence of "access"? Because later in the sequence you don't see this word anymore.
So: return a word if the rest of the sequence does not have this word.
This would be easy in LINQ, with recursion, but it is not very efficient: for every word you would have to check the rest of the sequence to see if the word is in the rest.
It would be way more efficient to remember the highest index on which you found a word.
As an extension method. If you are not familiar with extension methods, see extension methods demystified.
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source)
{
return FindLastOccurrences<T>(source, null);
}
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source,
IEqualityComparer<T> comparer)
{
// TODO: check source not null
if (comparer == null) comparer = EqualityComparer<T>.Default;
Dictionary<T, int> dictionary = new Dictionary<T, int>(comparer);
int index = 0;
foreach (T item in source)
{
// did we already see this T? = is this in the dictionary
if (dictionary.TryGetValue(item, out int highestIndex))
{
// we already saw it at index highestIndex.
dictionary[item] = index;
}
else
{
// it is not in the dictionary, we never saw this item.
dictionary.Add(item, index);
}
++index;
}
// return the keys after sorting by value (which contains the highest index)
return dictionay.OrderBy(keyValuePair => keyValuePair.Value)
.Select(keyValuePair => keyValuePair.Key);
}
So for every item in the source sequence, we check if it is in the dictionary. If not, we add the item as key to the dictionary. The value is the index.
If it is already in the dictionary, then the value was the highest index of where we found this item before. Apparently the current index is higher, so we replace the value in the dictionary.
Finally we order the key value pairs in the dictionary by ascending value, and return only the keys.

Select key and return value OR select value and return key

I imagine there is a very concise way to do this, but I'm new to .NET. I have a bunch of pairs for a mapping. The mapping works both ways though. I'd like to store them once, like this:
{"a", "a'"},
{"b", "b'"},
...
using a Dictionary or something. I know I can use linq to easily query a dictionary, but how can I conditionally have it return the key if I query a value or return the value if I input a key? For example, if input b', output b. If input a, output a'.
The data structure does not have to be a dictionary by the way. I just want the most concise way to store it and the most concise way to retrieve it. This is not performance intensive.
The most concise way is the use a Dictionary and put everything in it, for example:
{ "a", "a'" }
{ "a'", "a" }
{ "b", "b'" }
{ "b'", "b" }
Lookup and usage would be fast and clear
Create a dictionary extension method.
public static string Retrieve(this Dictionary<string,string> dictionary, string value)
{
var item = (from v in dictionary
where v.Key == value || v.Value == value
select (v.Key == value) ? v.Value : v.Key
).FirstOrDefault();
return item;
}

updating a KeyValuePair where the key is not an int

I am trying to make a change to a KeyValuePair and have got as far as this code from another post I found:
var keysToModify = this.Properties
.Where(k => k.Key == propertyName)
.ToList();
foreach (var key in keysToModify)
{
this.Properties[key] = newValue;
}
But my key field is a string not an int. What would I need to do to update a KeyValuePair in this case?
EDIT : My KeyValuePair is of type string,string, and when I run the code in my example above, I get the error :
keyvaluepair is not assignable to parameter type int
There is no particular magic to updating the value of the pair when the key is a string - it's much the same, you're just using a string to access a value (and this stands for any type being used as key, omitting any possible peculiarities).
But the only thing I can think might be throwing you off in this case is the loop. The loop is iterating instances, though, and isn't exposing an additive "index" in doing so, but rather key in this case would be a string.
The key wasn't an integer in your linked question either, it was a Customer.
You should be able to use the same general method no matter what the key type is.
Here's example code like the accepted answer to the other question that will work when the key is a string:
// The ToList() call here is important, so that we evaluate all of the query
// *before* we start modifying the dictionary
var keysToModify = CustomerOrderDictionary.Keys
.Where(k => k == "MyString")
.ToList();
foreach (var key in keysToModify)
{
CustomerOrderDictionary[key] = 4;
}
Note that where the other answer accessed the Id property of the Customer key, you can directly compare the key to your target string.
Also, note that if you are just updating a single entry in the dictionary you don't need a loop, you can just do it directly. If you know the dictionary dictionary has an entry with the given key, or don't mind creating a new entry, just use:
CustomerOrderDictionary["MyString"] = 4;
or, to guard against creating new entry:
if (CustomerOrderDicionary.ContainsKey("MyString"))
{
CustomerOrderDictionary["MyString"] = 4;
}

Get index of a key/value pair in a C# dictionary based on the value

I would like to know if some property or method exists that gets the index of a specific value.
I found that dictionaries have the Contains() method which returns true if the value passed in exists, so this method almost implements what I need.
I know that I can loop through all the value pairs and check the condition, but I ask because maybe there's an optimized way of doing this.
Let's say you have a Dictionary called fooDictionary
fooDictionary.Values.ToList().IndexOf(someValue);
Values.ToList()
converts your dictionary values into a List of someValue objects.
IndexOf(someValue)
searches your new List looking for the someValue object in question
and returns the Index which would match the index of the Key/Value pair in the dictionary.
This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.
This does not however account for the issue that there may be several matching "someValue" objects.
There's no such concept of an "index" within a dictionary - it's fundamentally unordered. Of course when you iterate over it you'll get the items in some order, but that order isn't guaranteed and can change over time (particularly if you add or remove entries).
Obviously you can get the key from a KeyValuePair just by using the Key property, so that will let you use the indexer of the dictionary:
var pair = ...;
var value = dictionary[pair.Key];
Assert.AreEqual(value, pair.Value);
You haven't really said what you're trying to do. If you're trying to find some key which corresponds to a particular value, you could use:
var key = dictionary.Where(pair => pair.Value == desiredValue)
.Select(pair => pair.Key)
.FirstOrDefault();
key will be null if the entry doesn't exist.
This is assuming that the key type is a reference type... if it's a value type you'll need to do things slightly differently.
Of course, if you really want to look up values by key, you should consider using another dictionary which maps the other way round in addition to your existing dictionary.
Consider using System.Collections.Specialized.OrderedDictionary, though it is not generic, or implement your own (example).
OrderedDictionary does not support IndexOf, but it's easy to implement:
public static class OrderedDictionaryExtensions
{
public static int IndexOf(this OrderedDictionary dictionary, object value)
{
for(int i = 0; i < dictionary.Count; ++i)
{
if(dictionary[i] == value) return i;
}
return -1;
}
}
You can find index by key/values in dictionary
Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("a", "x");
myDictionary.Add("b", "y");
int i = Array.IndexOf(myDictionary.Keys.ToArray(), "a");
int j = Array.IndexOf(myDictionary.Values.ToArray(), "y");
You can use LINQ to help you with this.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "hi");
dict.Add(2, "NotHi");
dict.Add(3, "Bah");
var item = (from d in dict
where d.Value == "hi"
select d.Key).FirstOrDefault();
Console.WriteLine(item); //Prints 1
If searching for a value, you will have to loop through all the data. But to minimize code involved, you can use LINQ.
Example:
Given Dictionary defined as following:
Dictionary<Int32, String> dict;
You can use following code :
// Search for all keys with given value
Int32[] keys = dict.Where(kvp => kvp.Value.Equals("SomeValue")).Select(kvp => kvp.Key).ToArray();
// Search for first key with given value
Int32 key = dict.First(kvp => kvp.Value.Equals("SomeValue")).Key;
In your comment to max's answer, you say that what you really wanted to get is the key in, and not the index of, the KeyValuePair that contains a certain value. You could edit your question to make it more clear.
It is worth pointing out (EricM has touched upon this in his answer) that a value might appear more than once in the dictionary, in which case one would have to think which key he would like to get: e.g. the first that comes up, the last, all of them?
If you are sure that each key has a unique value, you could have another dictionary, with the values from the first acting as keys and the previous keys acting as values. Otherwise, this second dictionary idea (suggested by Jon Skeet) will not work, as you would again have to think which of all the possible keys to use as value in the new dictionary.
If you were asking about the index, though, EricM's answer would be OK. Then you could get the KeyValuePair in question by using:
yourDictionary.ElementAt(theIndexYouFound);
provided that you do not add/remove things in yourDictionary.
PS: I know it's been almost 7 years now, but what the heck. I thought it best to formulate my answer as addressing the OP, but of course by now one can say it is an answer for just about anyone else but the OP. Fully aware of that, thank you.
no , there is nothing similar IndexOf for Dictionary although you can make use of ContainsKey method to get whether a key belongs to dictionary or not

How do I select a List from something like new Dictionary(int, List<Customer>);

Dictionary<int, List<Customer>> dictionary = new Dictionary<int, List<Customer>>();
I want to query based on the key and get a List back. Not sure how to structure the LINQ query for that.
Desired Output:
A List<Customer> for a particular key in the Dictionary.
That's what the Dictionary (as you've defined the generic arguments) will do. So, dictionary[key] will return the list. Note that it will throw an exception if you haven't initialized it already with dictionary[key] = new List<Customer>();.
You don't need to use LINQ for this, but if you really want to
int key = 1;
List<Customer> customers = dictionary.Single(item => item.Key == key).Value;
The simplest way is to just retrieve the value for the key using the regular [] operator
dictionary[key];

Categories