Im have setup a nested Dictionary as follows:
static Dictionary<string, Dictionary<UInt32, TClassType> > m_dictionary = new Dictionary<string, Dictionary<UInt32, TClassType>>();
The "TClassType" contains three attributes:
Title (string)
code (uint)
Address (string)
I add value to this nested structure as follows:
TClassType newEntry = new TClassType(s_title, ui_code, s_address)
if (! m_dictionary.ContainsKey(s_title))// check as the same s_title can occur multiple times but have different ui_code and s_address values
{
m_dictionary.Add(s_title, new Dictionary<uint, TClassType>());
}
m_dictionary[s_title].Add(ui_code, s_address);
Now my question is what is a good way to access all of the values for a specific key [s_title]?
the key [s_title] will contain many items within the nested Dictionary, and for a unique [s_title] entry I would like to obtain all of the relevant keys and values related to this outter key from within the nested Dictionary.
Sorry I hope that's not confusing, I find it as hard to ask as I do trying to implement.
Thank you all in advance
Try this:
if (m_dictionary.Contains(s_title))
foreach(TClassType entry in m_dictionary[s_title].Values)
// Do something with the entry.
Have you used linq before? This would be a prime usage for groupby. What you're doing adds a level of convolution.
With your current setup if you have a list of TClassType you would be able to use the linq where expression to grab only those with the title you are looking for and then the ui_code you need.
Edit for example (I was on mobile before which is hard to code on :))
IEnumerable<TClassType> entries = entriesList;//whatever you use to populate the entries
var titles = entries.Where(x=> x.s_title == "Title you're looking for").Distinct();
Related
I have a C# custom object collection which has a property name ISBN. I also have a variable which has some but not all of the ISBN's in the form of List. I want to order the custom object collection such that those usernames in the List are listed first followed by others. I did something like the following:
var allBooks = GetAllBooks();
//First show the books popular among your friends followed by others from isbnList.
var priorityList = allBooks.Where(p => isbnList.Contains(p.ISBN)).ToList();
var otherList = allBooks.Where(p => !isbnList.Contains(p.ISBN)).ToList();
priorityList.AddRange(otherList);
return priorityList;
Essentially first I am getting subset of the object list corresponding to List followed by the rest. Then I am combining both the list and return the entire list. I am not sure whether this is the correct way of doing it or not. Also, I am not sure, once combined, will it retain the order in which the items were added or it will create its own order.
Thanks
You can use OrderBy(Descending)/ThenBy(Descending) with bool. false will be before true, so to get correct order you need OrderByDescending:
var allBooks = GetAllBooks();
//First show the books popular among your friends followed by others from isbnList.
var priorityList = allBooks.OrderByDescending(p => isbnList.Contains(p.ISBN)).ToList();
BACKGROUND TO THE PROBLEM
Say I had the following two lists (prioSums and contentVals) compiled from a SQL Server CE query like this:
var queryResults = db.Query(searchQueryString, searchTermsArray);
Dictionary<string, double> prioSums = new Dictionary<string, double>();
Dictionary<string, string> contentVals = new Dictionary<string, string>();
double prioTemp = 0.0;
foreach(var row in queryResults)
{
string location = row.location;
double priority = row.priority;
if (!prioSums.ContainsKey(location))
{
prioSums[location] = 0.0;
}
if (!contentVals.ContainsKey(location))
{
contentVals[location] = row.value;
prioTemp = priority;
}
if (prioTemp < priority)
{
contentVals[location] = row.value;
}
prioSums[location] += priority;
}
The query itself is pretty large, very dynamically compiled, and really beyond the scope of this question, so I'll just say that it returns rows that include a priority, text value, and location.
With the above code I am able to get one list (prioSums) which sums up all of the priorities for each location (not allowing repeats on the location [key] itself, even though repeats for the location are in the query results), and another list (contentVals) to hold the value of the location with the highest priority, once again, using the location as key.
All of this I have accomplished and it works very well. I can iterate over the two lists and display the information I want HOWEVER...
THE PROBLEM
...Now I need to reorder these lists together with the highest priority (or sums of priorities which are stored as the values in prioSums) first.
I have wracked my brain trying to think about using an instantiated class with three properties as given advice by others, but I can't seem to wrap my brain on how that would work, given my WebMatrix C#.net-webpages environment. I know how to call a class from a .cs file from the current .cshtml file, no problem, but I have never done this by instantiating a class to make it an object before (sorry, still new to some of the more complex C# logic/methodology).
Can anyone suggest how to accomplish this, or perhaps show an easier (at least easier to understand) way of doing this? In short all I really need is these two lists ordered together by the value in prioSums from highest to lowest.
NOTE
Please forgive me if I have not provided quite enough information. If more should be provided don't hesitate to ask.
Also, for more information or background on this problem, you can look at my previous question on this here: Is there any way to loop through my sql results and store certain name/value pairs elsewhere in C#?
I dont know if its the outcome you want but you can give it a try:
var result = from p in prioSums
orderby p.Value descending
select new { location = p.Key, priority = p.Value, value = contentVals[p.Key] };
My data source could have duplicate keys with values.
typeA : 1
typeB : 2
typeA : 11
I chose to use NameValueCollection as it enables entering duplicate keys.
I want to remove specific key\value pair from the collection, but NameValueCollection.Remove(key) removes all values associated with the specified key.
Is there a way to remove single key\value pair from a NameValueCollection,
OR
Is there a better collection in C# that fits my data
[EDIT 1]
First, thanks for all the answers :)
I think I should have mentioned that my data source is XML.
I used System.Xml.Linq.XDocument to query for type and also it was handy to remove a particular value.
Now, my question is, for large size data, is using XDocument a good choice considering the performance?
If not what are other alternatives (maybe back to NameValueCollection and using one of the techniques mentioned to remove data)
The idea of storing multiple values with the same key is somehow strange. But I think you can retrieve all values using GetValues then remove the one you don't need and put them back using Set and then subsequent Add methods. You can make a separate extension method method for this.
NameValueCollection doesn't really allow to have multiple entries with the same key. It merely concatenates the new values of existing keys into a comma separated list of values (see NameValueCollection.Add.
So there really is just a single value per key. You could conceivably get the value split them on ',' and remove the offending value.
Edit: #ElDog is correct, there is a GetValues method which does this for you so no need to split.
A better option I think would be to use Dictionary<string, IList<int>> or Dictionary<string, ISet<int>> to store the values as discrete erm, values
You may convert it to Hashtable
var x = new NameValueCollection();
x.Add("a", "1");
x.Add("b", "2");
x.Add("a", "1");
var y = x.AllKeys.ToDictionary(k => k, k=>x[k]);
make your own method, it works for me --
public static void Remove<TKey,TValue>(
this List<KeyValuePair<TKey,TValue>> list,
TKey key,
TValue value) {
return list.Remove(new KeyValuePair<TKey,TValue>(key,value));
}
then call it on list as --
list.Remove(key,value); //Pass the key value...
Perhaps not the best way, but....
public class SingleType
{
public string Name;
public int Value;
}
List<SingleType> typeList = new List<SingleType>();
typeList.Add (new SingleType { Name = "TypeA", Value = 1 });
typeList.Add (new SingleType { Name = "TypeA", Value = 3 });
typeList.Remove (typeList.Where (t => t.Name == "TypeA" && t.Value == 1).Single());
You can use the Dictionary collection instead:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("typeA", 1);
dictionary.Add("typeB", 1);
When you try to insert type: 11 it will throw exception as Key already exists. So you can enter a new key to insert this data.
Refer this Tutorial for further help.
I have a Dictionary<int, int> and would like to update certain elements all at once based on their current values, e.g. changing all elements with value 10 to having value 14 or something.
I imagined this would be easy with some LINQ/lambda stuff but it doesn't appear to be as simple as I thought. My current approach is this:
List<KeyValuePair<int, int>> kvps = dictionary.Where(d => d.Value == oldValue).ToList();
foreach (KeyValuePair<int, int> kvp in kvps)
{
dictionary[KeyValuePair.Key] = newValue;
}
The problem is that dictionary is pretty big (hundreds of thousands of elements) and I'm running this code in a loop thousands of times, so it's incredibly slow. There must be a better way...
This might be the wrong data structure. You are attempting to look up dictionary entries based on their values which is the reverse of the usual pattern. Maybe you could store Sets of keys that currently map to certain values. Then you could quickly move these sets around instead of updating each entry separately.
I would consider writing your own collection type to achieve this whereby keys with the same value actually share the same value instance such that changing it in one place changes it for all keys.
Something like the following (obviously, lots of code omitted here - just for illustrative purposes):
public class SharedValueDictionary : IDictionary<int, int>
{
private List<MyValueObject> values;
private Dictionary<int, MyValueObject> keys;
// Now, when you add a new key/value pair, you actually
// look in the values collection to see if that value already
// exists. If it does, you add an entry to keys that points to that existing object
// otherwise you create a new MyValueObject to wrap the value and add entries to
// both collections.
}
This scenario would require multiple versions of Add and Remove to allow for changing all keys with the same value, changing only one key of a set to be a new value, removing all keys with the same value and removing just one key from a value set. It shouldn't be difficult to code for these scenarios as and when needed.
You need to generate a new dictionary:
d = d.ToDictionary(w => w.Key, w => w.Value == 10 ? 14 : w.Value)
I think the thing that everybody must be missing is that it is exceeeeedingly trivial:
List<int> keys = dictionary.Keys.Where(d => d == oldValue);
You are NOT looking up keys by value (as has been offered by others).
Instead, keys.SingleOrDefault() will now by definition return the single key that equals oldValue if it exists in the dictionary. So the whole code should simplify to
if (dictionary.ContainsKey(oldValue))
dictionary[key] = newValue;
That is quick. Now I'm a little concerned that this might indeed not be what the OP intended, but it is what he had written. So if the existing code does what he needs, he will now have a highly performant version of the same :)
After the edit, this seems an immediate improvement:
foreach (var kvp in dictionary.Where(d => d.Value == oldValue))
{
kvp.Value = newValue;
}
I'm pretty sure you can update the kvp directly, as long as the key isn't changed
I have an array with values at meaningful indices. How can I tell if a particular there is a value at a particular element?
Array.Exists() is the closest I've found, but it looks overcomplicated for what I want, so I'm curious to know if it's really the best way.
UPDATE
OK, so I have an array of objects:
ImageGroup[] Images;
And the index of the elements corresponds to a feature of that item. In this case, the index refers to a value within the filename of the original image. When I come across a filename, I want to check if an element exists at the corresponding index and create one if not.
So I want to know if Images[someInt] exists.
Updated
With the last update this looks more like a dictionary (unless you're going in numerical order and not where "1,2,5" may have been populated, but 3,4 are absent and need to be created). If this is something where index could potentially skip, I would recommend a dictionary:
Dictionary<Int32,Image> images = new Dictionary<Int32, Image>();
// populated previously
Int32 needle = GetIndexOfImage(newImage);
if (!images.ContainsKey(needle))
images.Add(needle, newImage);
Then, once you're done populating, you can then re-reference the item by index in the following fashion:
images[specificIndex]
Once more, you can retrieve all the elements stored using the following as well:
images.Values
Some resources:
Dictionary
Dictionary.ContainsKey
First response:
if (a[index] == interesting) ....
After the Edit(s):
int index = GetIndexFromFilename(filename);
// if (Images[index] != null && Images[index] == interesting) ....
if (Images[index] == null)
Images[index] = CreateImage(filename);
But you should probably just use a Dictionary<string, Image> and use filename as the Key.
It sounds like what you're looking for is the functionality of a dictionary. It would be extremely helpful if you posted how you're populating your array, and how you want to be able to index it. From what I can gather, this is how I would implement...
Dictionary<SomeEnum, ImageGroup> images = new Dictionary<SomeEnum, ImageGroup>();
foreach(SomeEnum enumValue in Enum.GetValues(typeof(SomeEnum)))
{
ImageGroup group = BuildImageGroup();
images.Add(enumValue, group);
}
then you can do:
...
if(images.ContainsKey(SomeEnum.SomeValue))
return images[SomeEnum.SomeValue];
else
return DoSomethingFancy();
If you have multiple image groups for a single enum value (collisions), then you can use a collection of ImageGroups in the dictionary, like this:
Dictionary<SomeEnum, ImageGroup[]>