Half the time I need to find a value based on string, their name, and the other half I need to find a value based on an int, their user ID.
Currently I have two dictionaries to solve this dilemma - one that uses a string as a key and one that uses an int as a key. I was wondering if there is a more efficient way to do this - a way to get a value based on int or string.
public static Dictionary<int, Player> nPlayers = new Dictionary<int, Player>();
public static Dictionary<string, Player> sPlayers = new Dictionary<string, Player>();
After scanning the other questions, someone mentioned using a dictionary of dictionaries. If anyone can elaborate on this (if it's the solution I'm looking for), that'd be grand
I don't know much about a tuple, but from what I understand it requires two keys, and what I am looking for takes one or the other.
Would Dictionary<object, Player> do the trick? I have no idea.
Please help me in my narrow-minded coding experience. ;_;
As per your comment when user logged in to system you adding them to a dictionary, here you have to add to both dictionaries.
I think you can do this in another way,
public static List<Player> nPlayers = new List<Player>();
That's only you need, add players when they logged in.
If you want to search by ID, Name or whatever you can query nPlayers and find the Player.
var playerByID = nPlayers.Where(p= p.ID==givenID).FirstOrDefault();
var playerByName = nPlayers.Where(p= p.Name==givenName).FirstOrDefault();
I don't think having a Dictionary<object,Player> is a better idea than having two distinct dictionaries. It will probably take the same amount of memory (since each Player reference will still be stored twice in the unified dictionary), will probably be less clear, and might (conceivably) cause problems with hashcode collisions since your key can be several different types.
I would just keep two dictionary, PlayersByName and PlayersByID, and use them when appropriate.
Do you want to know in the future the original data type that was put in the Dictionary? If not, you have two options:
Stringly typed! - Just use a string as the key and when adding to it, call .ToString() on the integers :)
Be objective - Use an object as the key, that way you can put anything you like inside it.
Based on the 2, I'd recommend the first as you still have some kind of type restrictions in there.
If you do want to know the original data type in the future - your implementation is fine :)
Your solution (2 dictionaries) is correct one. Dictionary can only be indexed by one stable key. As result you have to keep separate dictionaries to index by different keys.
Related
I'm trying to come up with a good model for (what I would consider) a somewhat complicated class. There are two entities which are independent of each other (in that they have use, by themselves, elsewhere in the app), a User Group and an Event Type.
A User Group has a list of event types to which they are entitled. And beyond that, there is a list of strings which applies to each combination of User Group and Event which tells the app strings to replace later on (so a Dictionary where they key is a field to replace and the value is the value to replace it with).
I come from more of a SQL background, so it's easy for me to think in terms of tables and primary keys. This structure would be keyed off UserGroupID, EventTypeID, NameToReplace, but when I try to come up with a way to do it in C#, I end up with ugly (or at least I think they're ugly) structures like Dictionary<int, Dictionary<tuple<int, string>, string>> or Dictionary<int, Dictionary<int, Dictionary<string, string>>>
I could also do away with the dictionary concept and just make a list of tuples, or a list of custom classes which tie all the logical "keys" together.
My question(s) come down to, is this sort of nested collection structure common and/or a good idea? Are there best practices when modeling data like this anyone can point me to?
Thanks in advance!
So, this might be controversial, but I wanted to put this version out for discussion, to know how appropriate this approach would be.
Assuming you don't have millions of groups and event types, you could pack those into kind of Composite Key in db terms with bits shift :
public static int Combine(int value1, int value2)
{
return value1 | (value2 << 8);
}
Then Dictionary<int, string> would be work fine.
dictionary.Add(Combine(UserGroupID, EventTypeID), NameToReplace)
And to get the value :
dictionary[Combine(UserGroupID, EventTypeID)] // Or TryGetValue()
So I am attempting to write a program that combines a PDF from a list of PDF's that are already available. I've got most of it done to this point, but I'm having an issue with one step in particular. I'm also writing this in c# if that isn't apparent.
I have an array of strings that contains a category name, and for each category name I want to create a variable of type PdfOutline that gets initialized to null that I can iterate through later in the program.
I've tried to look into this myself and it seems like dictionary is the way to do it, but I'm not really sure how to go about it. Firstly, is making a dictionary the right way to do it and secondly I need help with implementation.
Thanks for your time!
Something like the following would work (not syntax-checked this, sorry):
// This requires the array of Categories to have no duplicates.
public Dictionary<string, PdfOutline> BuildUpMyCollectionOfOutlines(string[] categories)
{
return categories.ToDictionary(cat => new KeyValuePair<string, PdfOutline>(cat, null));
}
If you do it this way, then you can later consume the result as such (although having a function to do this is silly, is just my way to show you how to consume it):
public PdfOutline GetOutlineByCategory(Dictionary<string, PdfOutline> outlines, string category)
{
// This will be problematic if the category isn't actually in the dictionary.
return outlines[category];
}
Whether you should use a Dictionary<string, PdfOutline> versus something else, like a List<KeyValuePair<string, PdfOutline>> depends on 1) how many of these you'll have and 2) how you'll be accessing them. For example, if you have 10,000 of them and you need to randomly and repeatedly find them by Category name, then the Dictionary is the right approach because it hashes things for quicker searching (think an index in a table in a database). However, if you have 10,000 but only need to find 2 of them, or vice versa, only have 10 of them, then the overheads in building up that quick-searching capability is wasted. So Dictionary vs other is best answered by the question, "If this was in a database table, would you index it?"
I have a List of Dictionaries, List<Dictionary<String,Object>>. The key is an identifier of some abstract record. These Dictionaries come from various places. The size of each Dictionary is in the range [0, 1000].
All Dictionaries contain unique keys. After accumulating some Dictionaries I must make a search by key. It could be done by iterating the List and calling search method on every Dictionary or it could be done by copying all Dictionaries into one. These approaches do not offer very good performance. I am interested in ways to optimize this task.
Edit:
Thank you guys! Maybe I'll change the accumulation method and as result eliminate the problem itself!
Are you expecting there to be lots of key fetches after an initial population phase? If so, amalgamate everything into a single dictionary. If you'll only be doing a few fetches, I can't see any way you could get better than asking every dictionary.
Of course you could create a hybrid approach: create a new (initially empty) dictionary for the amalgamated results, and populate it as you're asked for keys - by searching through all the rest each time you're asked for a key which isn't already in your "big" dictionary.
Is there no way of predicting which dictionary would have a particular key?
If there is any way to localize a dictionary of interest by specifying a key, you can try, naturaly, to create a cross association table where you can try to match the key to dictionary.
If not, imho, don't see any other option that just iterate over collection and ask for the key , may be using standart for and not nicer linq coding.
Adding to what Jon said, there is an API called as PowerCollections which contains MultiDictionary. If my memory is not corrupted, I believe, you can use this for the purpose mentioned.
http://powercollections.codeplex.com/discussions/242163
It sounds like you have lots of dictionaries to "speed up" (assumption of motive) searches that are limited to certain "abstract record" types.
You can get away with one single dictionary, but on limited searches check the result is required abstract record type after finding it. Rather than maintaining a single dictionary for each and every abstract record type as at present.
Basically I have a Dictionary<Guid, Movie> Movies collection and search for movies using Guid, which is basically movie.Guid. It works great, but I also want to be able to search the same dictionary using movie.Name without looping through each element.
Is this possible or do I have to create another Dictionary<K, V> for this?
Just have two Dictionaries, one of them having the guid as its key and the other with the name as its key.
If you don't want to look at every element, you need to index it the other direction. This means another Dictionary to get O(1).
You can iterate across the variables but then you arnt getting the constant-time searching value in a dictionary (because of the way that the keys are hashed.) The answer above regarding using two dictionarys to hash references to your object may be a good solution if you dont have too many objects to reference.
You could search with the Values property:
dictionary.Values.Where(movie => movie.Name == "Some Name")
You'll lose the efficiency of a key based look up, but it will still work.
Since dictionaries are for one-way mapping you can't get keys from values.
You'll need two dictionaries.
There is also a suggestion:
You can use a custom hash function for keys instead of GUIDs and store Movie Names hash as keys. Then you can actually perform two way search in your dictionary.
Rather than using two dictionaries, you'd be much better off using one container class that has two dictionaries inside it.
Some guy named Jon came up with a partial solution to this (which you could easily build upon), leaving his code here: Getting key of value of a generic Dictionary?
You can't use that dictionary to do that search with anything like the same efficiency. But you can easily just run a LINQ query against your dictionary's Values property, which is just collection of the Movie values.
var moviesIWant = From m in movieLookup.Values
Where m.Name == "Star Wars"
Select m
Some thoughts:
When you find your answer though, you would not have the guids, unless they were also a property of movie.
For a small dictionary, this is just fine. For large and repeated searches, you should consider the creation of other dictionaries keyed on the other values you wish to search on. Only in this way would you achieve the speed of a guid lookup comparable to your original dictionary.
You could create another dictionary keyed by Name. Once you've done this, you could search this dictionary by it's key and it would have the same super-efficiency of your original dictionary, even for a very large dictionary.
var moviesByName = movieLookup.Values.ToDictionary(m => m.Name, m => m)
No I don't believe it is possible. You'll have to use another dictionary.
If you are going to want to search on more movie attributes you may be better off moving the data down to a database and use that for querying. That is what databases are good for after all.
I want to build 2-dimentional collection where i need unique combination of key value pairs. For example Domain "Company" (Id: 1) can have MachineName "Machine1" and "Machine2", but cannot add another MachineName "Machine1" again. Another Domain "Corporate" (Id:2) can have another machineName "Machine1".
here my collection will be like this 1-Machine1, 1-Machine2, 2-Machine1.
Adding 1-Machine1 or 2-Machine1 should be invalid entry.
Please suggest datatype or approach for this.
I cannot use Dict> datatype, because it may hamper performance if size grows.
So you need some kind of collection with a unique key, and each item within this collection is unique.
So really, you're talking about a dictionary where the value within the dictionary is a unique collection.
Assuming you're only talking about strings, I'd be using something like:
Dictionary<string, HashSet<string>>
Someone correct me if I'm wrong, but I think the advantage of using these generic structures is you can (right off the bat), do this:
Dictionary<string, HashSet<string>> domains = new Dictionary<string, HashSet<string>>();
domains["Domain1"].Add("Machine1");
I'm sorry, but from your description it still sounds like a Dictionary implementation would be a good fit.
If and when the performance of the application suffers due to the speed of the dictionary, then you can revisit the problem and roll your own specifically tailored solution.
You could do something like this:
Dictionary<String, List<String>> mapping = new Dictionary<string, List<string>>();
mapping.Add("1",new List<string>());
mapping["1"].Add("Machine1");
mapping["1"].Add("Machine2");
This will give you a one to many mapping between domain and machines.
or the NameValueCollection class would do the same.
Do you need to be able to look up the list of domains with given machine name efficiently? Otherwise a Hashtable<String, HashSet<String>> seems like a good fit.
There also seems to be something called NameValueCollection which might be a good fit if you change the defaults so that it isn't case- or culture-sensitive.
You didn't state this as a requirement, but my guess is that you also need to be able to query the data structure for all of the machines for a specific "domain". Ex. list the machines belonging to Company 1. This is the only reason I can think of where the performance of using a Dictionary might be unacceptable (since you would have to traverse the entire list to find all of the matching entries).
In that case you might consider representing the data as a tree.
Edit:
Based on your comment above, you could just concatenate your keys as a string and use a HashSet to check if you've already stored that key.