Get all Keys from a MultiDictionary - c#

Im looking for a way to get all FIRST level Keys of a multiDictionary and im totaly unable to get them (its for debugging purpose)
i declared the dictionary like this :
private Dictionary<string, Dictionary<string, Packet>> PacketsStore = new Dictionary<string, Dictionary<string, Packet>>();
So how can i print out a list of all the base keys?
how could i then print out the second level keys incase i need it too later...
thanks in advance!

First level, the well-known way:
var allKeys = PacketsStore.Keys;
Sub-dictionary keys, the LINQ way:
var allSubKeys = PacketsStore.SelectMany(pair => pair.Value.Keys);
OP has commented out on other answer that the two nested foreach loops were more suitable for debugging purposes, but, after all, if OP wants to output all subkeys to console, it can still be done with a one-liner solution:
// One-liner solution!
PacketsStore.SelectMany(pair => pair.Value.Keys).ToList().ForEach(Console.WriteLine);

foreach(KeyValuePair<string, Dictionary<string, Packet>> entry in PacketsStore)
{
string key = entry.Key; // first level
foreach(KeyValuePair<string, Packet> entryInner in entry.Value)
{
string keyInner = entryInner.Key // second level
}
}
I have taken keys into variables you can take the same into some collection. Purpose was to get keys :)

For all keys, try:
var keys = PacketsStore.Keys.ToArray();
and for second level keys:
List<string> secondaryKeys;
foreach (var key in keys)
{
secondaryKeys.AddRange(PacketStore[key].Keys.ToArray());
}

Related

c# loop through dictionary passed through session

I created and added items to this dictionary and set it to session. Now I'm trying to retrieve the session in another page and loop through the dictionary, how do I do so? I tried using foreach loop but the membersDictionary variable seems to be not a dictionary, how do I loop through the dictionary passed to session? Please help, thanks.
Home.aspx.cs
Dictionary<string, string> membersDictionary = new Dictionary<string, string>();
membersDictionary.Add(TB_member1Username.Text, TB_member1mobile.Text);
membersDictionary.Add(TB_member2Username.Text, TB_member2mobile.Text);
Session["FamPlanMembersDict"] = membersDictionary;
Home2.aspx.cs
var membersDictionary = Session["FamPlanMembersDict"];
foreach(var item in membersDictionary)
{
.....
}
Cast it as a dictionary of two strings as follows:
Dictionary<string, string> membersDictionary = Session["session_values"] as Dictionary<string, string>;
foreach(var item in membersDictionary)
{
.....
}
One way would be to cast it
var membersDictionary = (Dictionary<string, string>)Session["FamPlanMembersDict"];
foreach(var item in membersDictionary)
{
.....
}
Though quite old the documentation also states the same. The Session output is object as we wanted to be able to save everything there.

Dictionary look up where we want the keys contained in a string

I have a dictionary containing keys, e.g.
"Car"
"Card Payment"
I have a string description, e.g. "Card payment to tesco" and I want to find the item in the dictionary that corresponds to the string.
I have tried this:
var category = dictionary.SingleOrDefault(p => description.ToLowerInvariant().Contains(p.Key)).Value;
This currently results in both "Car" and "Card Payment" being returned from the dictionary and my code blows up as I have SingleOrDefault.
How can I achieve what I want? I thought about prefixing and suffixing the keys in spaces, but I'd have to do the same to the descriptions - I think this would work but it is a bit dirty. Are there any better ways? I have no objections of changing the Dictionary to some other type as long as performance is not impacted too much.
Required Result for above example: only get "Card Payment"
You can try to use linq OrderByDescending and Take after your where condition. to find the most match word value.
var category = dictionary
.Where(p => description.ToLowerInvariant().Contains(p.Key.ToLowerInvariant()))
.OrderByDescending(x => x.Key.Length)
.Take(1);
c# online
I would use List<string> to contain your keys, because there isn't any reason need to use a key and value collection.
List<string> keys = new List<string>();
keys.Add("Car");
keys.Add("Card Payment");
string description = "Card payment to tesco";
var category = keys
.Where(p => description.ToLowerInvariant().Contains(p.ToLowerInvariant()))
.OrderByDescending(x => x.Length)
.Take(1)
.FirstOrDefault();
NOTE
OrderBy key values length desc can make sure which key is the most match word value.
Here I'm using List<string> keys and System.Text.RegularExpressions find desired key.Try it.
string description = "Card payment to tesco";
List<string> keys = new List<string> {
{"Car" }, {"Card Payment" }
};
string desc = description.ToLowerInvariant( );
string pattern = #"([{0}]+) (\S+)";
var resp = keys.FirstOrDefault( a => {
var regx = new Regex( string.Format( pattern, a.ToLowerInvariant( ) ) );
return regx.Match( desc ).Success;
} );
Check here .NET Fiddle
You are abusing dictionaries. You will get no performance gain from dictionaries by scanning the keys. Even worse, a simple list would be faster in this case. Dictionaries approach a constant time access (O(1)) if you look up a value by the key.
if (dictionary.TryGetValue(key, out var value)) { ...
To be able to use this advantage you will need a more subtle approach. The main difficulty is that sometimes keys might consist of more than a single word. Therefore I would suggest a two level approach where at the first level you store single word keys and at the second level you store the composed keys and values.
Example: Key value pairs to be stored:
["car"]: categoryA
["card payment"]: categoryB
["payment"]: categoryC
We build a dictionary as
var dictionary = new Dictionary<string, List<KeyValuePair<string, TValue>>> {
["car"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("car", categoryA)
},
["card"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("card payment", categoryB)
},
["payment"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("card payment", categoryB),
new KeyValuePair("payment", categoryC)
}
};
Of course, in reality, we would do this using an algorithm. But the point here is to show the structure. As you can see, the third entry for the main key "payment" contains two entries: One for "card payment" and one for "payment".
The algorithm for adding values goes like this:
Split the key the be entered into single words.
For each word, create a dictionary entry using this word as main key and store a key value pair in a list as dictionary value. This second key is the original key possibly consisting of several words.
As you can imagine, step 2 requires you to test whether an entry with the same main key is already there. If yes, then add the new entry to the existing list. Otherwise create a new list with a single entry and insert it into the dictionary.
Retrieve an entry like this:
Split the key the be entered into single words.
For each word, retrieve the existing dictionary entries using a true and therefore fast dictionary lookup(!) into a List<List<KeyValuePair<string, TValue>>>.
Flatten this list of lists using SelectMany into a single List<KeyValuePair<string, TValue>>
Sort them by key length in descending order and test whether the description contains the key. The first entry found is the result.
You can also combine steps 2 and 3 and directly add the list entries of the single dictionary entries into a main list.

How to get a values list from a dictionary where the key matches in a list in c#

I have a dictionary and I want to retrieve all the values list from the dictionary based on a condition on the key, i.e. I want to retrieve only the values for which the respective key matches in alist.
Example: dictionary is as follows
IDictionary<string, string> maskingValues = new Dictionary<string, string>();
maskingValues.Add("cat", "Me#ena");
maskingValues.Add("dog", "N&avya");
maskingValues.Add("llama", "vivek!a");
maskingValues.Add("iguana", "sh^ams");
and I have list of strings as
List<string> keysString = new List<string>();
keysString.Add("cat");
keysString.Add("fox");
Now my requirement is to get the values list from the dictionary where the key matches from the keysString list.
The output should be
Me#ena
till now what I have done is
var all_parameters = maskingValues .Keys.ToList();
var parameters_to_mask = all_parameters.Intersect(keysString);
var values_list = parameters_to_mask.Where(k => data_dictionary.ContainsKey(k)).Select(k => data_dictionary[k]);
so values_list will contain the output Me#ena, I retrieved all the keys from the dictionary and then compared the keys list with the keysString list and then retrieved the values list from the output of the two list's intersect. But can I do it in more optimized way so that the code and the performance is good.
Thanks in advance. Please help me out.
This should work:
var q = maskingValues.Where(x => keysString.Contains(x.Key)).Select(x => x.Value);
foreach (var item in q)
{
Console.WriteLine(item);
}
There are a lot of solutions. This one for example:
var newlist = maskingValues.Where(x => keysString.Contains(x.Key)).Select(y=>y.Value).ToList();
I came up with a quick bit of code to do this fully using linq.
keysString.Where(x => maskingValues.Keys.Contains(x)).ToList().ForEach(x => Console.WriteLine(maskingValues[x]));
Not sure I got the spec right but this is faster than linq:
var matches = new List<string>();
foreach (var key in keysString)
{
if (maskingValues.TryGetValue(key, out string value))
{
matches.Add(value);
}
}
If your dictionary is large, you can improve performance by taking advantage of the fact that accessing an element by key in a dictionary is O(
var result = keysString
.Select(k =>
{ string value;
maskingValues.TryGetValue(k, out value);
return value;
})
.Where(v => v != null);
... etc ...
Note that using TryGetValue is more efficient than calling Contains then the dictionary indexer.
This Should Work:
Below Solution is used when you know your Key name and want to retrive value of key
string objectValue;
maskingValues.TryGetValue("cat", out objectValue);
If you want to Retrive All values from Dictionary than used single line of code: maskingValues.Values

Sorted-ception - Adding to a SortedList inside a SortedDictionary

So this is a thing I've been looking at for quite some time now. And I can't see where I did it wrong. Hope you guys can help ^^
So my problem is that I have 311 objects which I try to sort into a SortedDictionary<int, SortedList<int, Entry>> (>). However the result is a dictionary with only 112 objects. Where do the rest go and why ain't they going where the should?
public SortedDictionary<int, SortedList<int, Entry>> GetSortedByForum(int id)
{
SortedDictionary<int, SortedList<int, Entry>> result = new SortedDictionary<int, SortedList<int, Entry>>();
foreach (var e in GetByForum(id))
{
e.fk_entry = e.fk_entry == null
? 0
: e.fk_entry;
if (!result.ContainsKey((int)e.fk_entry))
result[(int)e.fk_entry] = new SortedList<int, Entry>();
if (!result[(int)e.fk_entry].ContainsKey(e.fk_language))
result[(int)e.fk_entry][e.fk_language] = new Entry();
result[(int)e.fk_entry][e.fk_language] = e;
}
return result;
}
Background info might help:
fk_entry is the objects parent. An entry can only have on parent, but can however have multiple children.
fk_language is the language of the entry, a entry can have several translations
entry is an article of some sort. The dictionary should order them by parent, and then by language.
Your problem is in the following line of code. It only adds the first entry for a particular language - later entries for the same parent and language are not added.
if (!result[(int)e.fk_entry].ContainsKey(e.fk_language))
result[(int)e.fk_entry][e.fk_language] = new Entry();
Keeping as much of your code the same as possible, I think you want a collection of entries associated with each particular language:
var result = new SortedDictionary<int, SortedList<int, List<Entry>>>();
...
...
if (!result[(int)e.fk_entry].ContainsKey(e.fk_language))
result[(int)e.fk_entry][e.fk_language] = new List<Entry>();
result[(int)e.fk_entry][e.fk_language].Add(e);
Given your comment, "How would I do it if I wanted to also sort the different translations by fk_language?", you could try incorporating something like this into your loop:
var result2 = new SortedDictionary<int, Dictionary<int, List<int>>>();
if (!result2[(int)e.fk_entry].ContainsKey(e.some_unique_entry_id))
result2[(int)e.fk_entry][e.some_unique_entry_id] = new List<int>();
result2[(int)e.fk_entry][e.some_unique_entry_id].Add(e.fk_language);
Or use LINQ to query the first SortedDictionary, to manipulate it into the format you need.

Query dictionary with linq

I have a dictionary that gets built which is below
Dictionary<string, string> GTNMobilelist = new Dictionary<string, string>();
GTNMobilelist = LoadMobileNumbers();
i then need to query the Dictionary to check if a mobile number that has been enetered in to a textbox exists within the dictionary "Hope that makes sense" :-/
this is what i have
foreach (GridViewRow HandSetRow in grdvHandSets.Rows)
{
TextBox txtmobileNumber = (TextBox)HandSetRow.FindControl("txtmobilenumber");
//I need the linq statement here if the mobile number doesnt exists i need to
//throw an error saying mobile number doesnt exist within the dictionary
//iv been looking at linq statements for the past hour and im confused :(
}
Can any one help me on a quick solution for this?
There is no point using LINQ here. Use ContainsKey or ContainsValue instead.
if (!GTNMobilelist.ContainsValue(txtmobileNumber.Text))
ShowErrorMessage();
Next time, post your code so far, then we can point out any errors.
It is not clear to me if the phone number is in the key or in the value, but something like this should work.
Check by key:
string phoneNumberToLookFor = "12345678";
bool phoneNumberExists = GTNMobilelist.Any(kvp => kvp.Key == phoneNumberToLookFor);
Or, check by value:
string phoneNumberToLookFor = "12345678";
bool phoneNumberExists = GTNMobilelist.Any(kvp => kvp.Value == phoneNumberToLookFor);

Categories