Get values list from a key in Dictionary using LINQ - c#

I wrote the code below to get all the values from a dictionary which has the given key.
Dictionary<string,string> _dictionary;
public List<string> GetValuesUsingKey(string key)
{
List<string> outp = new List<string>();
foreach(var d in _dictionary)
{
if (d.Key == key)
{
outp.Add(d.Value);
}
}
return outp;
}
is there a simpler way to achieve this result using LINQ?
Update :
it turned out that i was mislearned about Dictionaries, i though i could use multiple values for a single key but i was wrong

A key in a Dictionary is guaranteed to be unique, so there's no need to return a List.
public string GetValueUsingKey(string key)
{
bool isKeyPresent = _dictionary.TryGetValue(key, out var output);
return isKeyPresent ? output : _YOUR_DEFAULT_BEHAVIOUR_;
}
The big advantage of a Dictionary is that the time complexity for insertion and retrieval of values using the key is O(1); if you cycle through all the KeyValuePair it contains you completely nullify the purpose of using a Dictionary as it would make the retrieval O(n)!

Dictionary is a one to one map, you cannot have multiple values for a given key.
ILookup on the other hand supports this scenario, as well as null keys:
using System.Linq;
class Element
{
public string Key { get; }
public string Value { get; }
...
}
IEnumerable<Element> elements = ...
ILookup<string, string> lookup = elements.ToLookup(e => e.Key, e => e.Value);
and then to get your result:
List<string> outp = lookup[key].ToList();

Related

Dictionary using a class as Parameter and Key, CRUD C#

So i need to create a data-structure with one Key, sub Key and Value. And a method to Add Key, sub Key and Value.
The Key are unique and can have multiple Sub Keys.
The Sub Key are uniques in the context inside Key and can have multiple Values.
The Values are unique inside the context of the Sub Key.
The first data-structure that comes to my mind was Dictionary (perform time is important for the task).
Then i created the following dictionary.
public class NewCollection : IHoplonCollection
{
class SubIndexAndValue
{
public int subIndex;
public List<string> Value = new List<string>();
}
class DataStructure : IComparable<DataStructure>
{
public string Key;
public List<SubIndexAndValue> subIndexValue = new List<SubIndexAndValue>();
public int CompareTo(DataStructure other)
{
if (Key.CompareTo(other.Key) > 0)
{
return 1;
}else if (Key.CompareTo(other.Key) < 0)
{
return -1;
}else
{
return 0;
}
}
}
SortedDictionary<DataStructure, SubIndexAndValue> colList = new SortedDictionary<DataStructure, SubIndexAndValue>();
public bool Add(string Key, int subIndex, string Value)
{
return true;
}
So as you can see the Add method will receive the Key, Sub Key and Value.
In the future i will need to do a CRUD and sort data.
My question is, how do i handle this? How can i use method like Contains() to check if one Value (string) was already inserted in the dictionary using this data-structure? Or maybe there is an easyer way to do this.
Thanks.
I think that a combination of built-in structures can solve your proposed datastructure:
Dictionary<string,Dictionary<int,HashSet<string>>>
The first dictionary holds list of key-value pairs of string (Key), and for every one of them, the value it's another Dictionary whose key is a unique string (SubKey) and the value is a HashSet<string>, a list of unique strings.

How to get a dictionary of dictionary properties values?

I have this:
public class GraphicsDraw
{
public Dictionary<int,GraphicItem> items { get; set; }
}
public abstract class GraphicItem
{
public float ItemSize { get; set; }
}
And I can access to all ItemSize's like this:
{
GraphicsDraw gd = new GraphicsDraw();
gd.items[i].ItemSize;
}
Is there any nice way that I can list ItemSize's down separately in another dictionary whit same key and ItemSize values?
Dictionary<int, float> ItemSize = items.(???)
Sure, using ToDictionary:
items.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ItemSize);
You can do, which uses LINQ,
Dictionary<int,float> itemSizes =
items.ToDictionary(item => item.Key, item => item.Value.ItemSize);
The ToDictionary accepts two delegates (or lambda expressions), the first one to select the key and the second one to select the value of the dictionary.
In your case you want to keep the same key, but change the value to the ItemSize property, thus the second expression.
You can simple use LINQ to extract necessary keys and values from items property.
items.ToDictionary(x => x.Key, x => x.Value.ItemSize);

Find Index from List

I have a Dictionary that contains thread Information Dictionary<String,Thread>
"2FF"
"2IE"
"7CH"
etc
what i know is integers 2,7 etc what i want to know that in Dictionary how many strings contain the given integer if it is there then get that string
Eg
String GetString(int integer)
{
//if Dictionary contains given intgr return whole string in which that integer is present
}
}
With LINQ syntax:
var matchingThreads = from pair in dictionary
where pair.Key.StartsWith(number.ToString())
select pair.Value;
With traditional syntax:
var matchingThreads = dictionary
.Where(pair => pair.Key.StartsWith(number.ToString()))
.Select(pair => pair.Value);
If you only need to count them and you don't care about the Thread objects, you can use:
int count = dictionary.Keys.Count(key => key.StartsWith(number.ToString()))
Note that you need a using System.Linq directive.
Maybe a List<CustomClass> would be a better choice here where CustomClass would look like:
public sealed class CustomClass
{
public Thread Thread { get; set; }
public string String { get; set; }
}
(Better property names are alway good, of course :-) )
A dictionary is not sutitable if you do not know the exact keys or only parts of them.
You could then use LINQ to find out what you want, e.g.:
int count = list.Where(c => c.String.StartsWith(integer.ToString())).Count();
//or
IEnumerable<string> strings = list.Where(c => c.String.StartsWith(integer.ToString())).Select(c => c.String);
public IEnumerable<string> GetMatchingKeys(int value)
{
var valueText = value.ToString();
return _dictionary.Keys.Where(key => key.Contains(valueText));
}

Sorting Hashtable by Order in Which It Was Created

This is similar to How to keep the order of elements in hashtable, except for .NET.
Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?
A NameValueCollection can retrieve elements by index (but you cannot ask for the index of a specific key or element). So,
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
Console.WriteLine("{0} = {1}", coll.GetKey(0), coll[0]); // prints "Z = 1"
However, it behaves oddly (compared to an IDictionary) when you add a key multiple times:
var coll = new NameValueCollection();
coll.Add("Z", "1");
coll.Add("A", "2");
coll.Add("Z", "3");
Console.WriteLine(coll[0]); // prints "1,3"
The behaviour is well documented, however.
Caution: NameValueCollection does not implement IDictionary.
As an aside: Dictionary<K,V> does not have any index you can use, but as long as you only add elements, and never remove any, the order of the elements is the insertion order. Note that this is a detail of Microsoft's current implementation: the documentation explicitly states that the order is random, so this behavior can change in future versions of the .NET Framework or Mono.
If this is something that you need to keep track of efficiently, then you are using the wrong data structure. Instead, you should use a SortedDictionary where the key is tagged with the index of when it was added (or a timestamp) and a custom IComparer that compares two keys based on the index (or the timestamp).
You can use a separate list to store the elements in the order they are added. Something along the lines of the following sample:
public class ListedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
List<TValue> _list = new List<TValue>();
Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey,TValue>();
public IEnumerable<TValue> ListedValues
{
get { return _list; }
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
_list.Add(value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
public bool Remove(TKey key)
{
_list.Remove(_dictionary[key]);
return _dictionary.Remove(key);
}
// further interface methods...
}
Is there any Hashtable or Dictionary in .NET that allows you to access it's .Index property for the entry in the order in which it was added to the collection?
No. You can enumerate over all the items in a Hastable or Dictionary, but these are not guaranteed to be in any sort of order (most likely they are not)
You would have to either use a different data structure altogether, (such as SortedDictionary or SortedList) or use a separate list to store the order in which they were added. You would want to wrap the ordered list and your dictionary/hashtable in another class to keep them synched.
Take a look at the OrderedDictionary class. Not only can you access it via keys, but also via an index (position).
An alternative is to create an array of stuctures, so instead of using
dictionary.Add{"key1","value1"}
you create a structure with the key/value like:
public struct myStruct{
private string _sKey;
public string sKey{
get { return _sKey; }
set { _sKey = value; }
}
private string _sValue;
public string sValue {
get { return _sValue; }
set { _sValue = value; }
}
}
// create list here
List<myStruct> myList = new List<myStruct>();
// create an instance of the structure to add to the list
myStruct item = new myStruct();
item.sKey = "key1";
item.sValue = "value1";
// then add the structure to the list
myList.Add(item);
Using this method you can add extra dimensions to the list without too much effort, just add a new member in the struct.
Note, if you need to modify items in the list after they have been added you will have to change the struct into a class. See this page for more info on this issue: error changing value of structure in a list

Is there a Dictionary<string, object> collection which allows multiple keys?

I currently have a menu with subitems that is being stored in this dictionary variable:
private Dictionary<string, UserControl> _leftSubMenuItems
= new Dictionary<string, UserControl>();
So I add views to the e.g. the "Customer" section like this:
_leftSubMenuItems.Add("customers", container.Resolve<EditCustomer>());
_leftSubMenuItems.Add("customers", container.Resolve<CustomerReports>());
But since I am using a Dictionary, I can only have one key named "customers".
My natural tendency would be to now create a custom struct with properties "Section" and "View", but is there a .NET collection is better suited for this task, something like a "MultiKeyDictionary"?
ANSWER:
Thanks maciejkow, I expanded your suggestion to get exactly what I needed:
using System;
using System.Collections.Generic;
namespace TestMultiValueDictionary
{
class Program
{
static void Main(string[] args)
{
MultiValueDictionary<string, object> leftSubMenuItems = new MultiValueDictionary<string, object>();
leftSubMenuItems.Add("customers", "customers-view1");
leftSubMenuItems.Add("customers", "customers-view2");
leftSubMenuItems.Add("customers", "customers-view3");
leftSubMenuItems.Add("employees", "employees-view1");
leftSubMenuItems.Add("employees", "employees-view2");
foreach (var leftSubMenuItem in leftSubMenuItems.GetValues("customers"))
{
Console.WriteLine(leftSubMenuItem);
}
Console.WriteLine("---");
foreach (var leftSubMenuItem in leftSubMenuItems.GetAllValues())
{
Console.WriteLine(leftSubMenuItem);
}
Console.ReadLine();
}
}
public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if (!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
public List<TValue> GetValues(TKey key)
{
return this[key];
}
public List<TValue> GetAllValues()
{
List<TValue> list = new List<TValue>();
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValues(key);
list.AddRange(values);
}
return list;
}
}
}
Answer 2:
Thanks Blixt for the tip about yield, here is GetAllValues with that change:
public IEnumerable<TValue> GetAllValues()
{
foreach (TKey key in this.Keys)
{
List<TValue> values = this.GetValuesForKey(key);
foreach (var value in values)
{
yield return value;
}
}
}
Answer 2 refactored further:
Here is a much more succinct way to do the same thing, thanks Keith:
public IEnumerable<TValue> GetAllValues()
{
foreach (var keyValPair in this)
foreach (var val in keyValPair.Value)
yield return val;
}
If you need variable number of values for one key, why not create Dictionary<string, List<UserControl>> ? Furthermore, you could inherit this class and create your own Add, get same syntax you're using now. This way you can avoid manual adding of empty lists before adding new control.
sth like this:
class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
if(!ContainsKey(key))
Add(key, new List<TValue>());
this[key].Add(value);
}
}
Check out NGenerics' HashList. It's a Dictionary which maintains a list of values for each key. Wintellect's PowerCollections library also has a handy MultiDictionary class which does things like automatically clean up when you remove the last value associated with a given key.
How about making the container value type a list:
private Dictionary<string, List<UserControl>> _leftSubMenuItems =
new Dictionary<string, List<UserControl>>();
if (!_leftSubMenuItems.ContainsKey("customers"))
{
_leftSubMenuItems["customers"] = new List<UserControl>();
}
_leftSubMenuItems["customers"].Add(container.Resolve<EditCustomer>());
_leftSubMenuItems["customers"].Add(container.Resolve<CustomerReports>());
Just a few tweaks...
public class MultiValueDictionary<TKey, TValue> :
Dictionary<TKey, List<TValue>>
{
public void Add(TKey key, TValue value)
{
List<TValue> valList;
//a single TryGetValue is quicker than Contains then []
if (this.TryGetValue(key, out valList))
valList.Add(value);
else
this.Add( key, new List<TValue> { value } );
}
//this can be simplified using yield
public IEnumerable<TValue> GetAllValues()
{
//dictionaries are already IEnumerable, you don't need the extra lookup
foreach (var keyValPair in this)
foreach(var val in keyValPair.Value);
yield return val;
}
}
The .NET framework 3.5 includes a special LINQ Lookup class.
It is similar to a dictionary except that it can handle multiple items with the same key. When you do a search using a given key, instead of receiving a single element, you receive a group of elements that match that key.
I read that it is a hashtable under the covers so it is fast for retrieving.
You use it something like this:
var example1 = (from element in ListWithDuplicates
select element)
.ToLookup(A => A.Name);
There are a bunch of caveats:
The Lookup class has no public constructor, so you cant just create a Lookup object, it seems to only be available using the .ToLookup syntax.
You cannot edit it once it has been created, no Add or Remove etc.
Apparently its not serializable
Using the grouped data can be a bit tricky
Theres a great article here discussing the Lookup and its implications in more detail.
No, there's no better built-in collection. I think your "natural tendency" is perfectly suited for solving this problem, as those are not really "same keys," but unique keys composed of different parts and Dictionary does the job. You can also nest dictionary (makes sense if you have large number of values for each name):
Dictionary<string, Dictionary<Type, object>> dict = ...;
var value = (T)dict[name][typeof(T)];
This approach will resolve to the element using a single hash table lookup. If you maintain a list of items for each element, you'll have to linearly traverse the list each time you need an element to lookup which defeats the purpose of using a Dictionary in the first place.
I don't know of a "MultiKeyDictionary". I'd recommend using a struct and overriding GetHashCode, Equals and implementing IEquatable<StructName> (which is used by Dictionary<TKey,TValue>).
Are you looking to store multiple entries per key together? Somethign like this ?

Categories

Resources