Override the specific dictionary, and leave the non-found keys - c#

I've a Dictionary<string, string> specDic that have the resource strings <Key,Value>, when I change the language of the app, it got new Dictionary<string, string> newDic that have the strings of the new language, but sometimes in the newDic we don't have keys that already in the specDic, in other words doesn't translated, I need to override the specDic with the newDic without override the non-found keys, I tried the following:
foreach (var item in newDic)
{
specDic[item.Key] = item.Value;
}
But, I don't loved what I did, does someone can suggest me a new way using linq or somthing?
Thanks

Turn your logic around, and look for each key from your original dictionary instead:
foreach (var key in specDic.Keys)
{
if (newDic.ContainsKey(key))
{
specDic[key] = newDic[key];
}
}
Now, if newDic contains a key matching one in specDic, the corresponding value in specDic will be overridden (or replaced, rather) by the value from newDic.
Values (keys) in specDic for which there is no corresponding value in newDic will remain as they are.

Related

Remove a single value from a NameValueCollection

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.

How delete items from Dictionary

I have
Dictionary<string, List<string>> Dic = new Dictionary<string, List<string>>();
How delete first 1,2,3 elements From Dic. I dont know how make it with "foreach"
foreach (KeyValuePair<string, List<string>> kvPair in Dic)
{
Console.WriteLine(kvPair.Key);
foreach (string str in kvPair.Value)
{
}
}
You can't get item 1,2,3 from the dictionary, you can only remove on the basis of a key.
Dictionary MSDN
The order in which the items are returned is undefined.
You may use Orderby to sort the dictionary on the basis of a key. But to remove an item from the dictionary you will need the key.
See Dictionary.Remove
EDIT: based on your edited question with "foreach"
You can't modify the dictionary while enumerating on it. If you try removing items from the dictionary in the foreach you will get error:
Collection was modified; enumeration operation may not execute.
You may convert the dictionary to an array and then remove the items from the dictionary (something like below, it may be improved or changed, it is just for an idea):
var dicArrray = Dic.ToArray();
foreach (KeyValuePair<string, List<string>> kvPair in dicArrray)
{
if (kvPair.Key.Equals("1"))
Dic.Remove(kvPair.Key);
}
But remember, the order in which the items will be in array is undefined. You can't be sure about it
as habib says you can not delete item from dictionary based upon index, you can only remove item based upon the key, use Remove() method
read more from here- Remove Item in Dictionary based on Value
first, create a collection of keys you want to remove:
var toDelete = new List<string>();
int count = 3;
foreach(var pair in dictionary) {
toDelete.Add(pair.Key);
count -= 1;
if( count==0 ) break;
}
// then when ready - delete
foreach(string key in toDelete) dictionary.Remove(key);
the reason is not to invalidate dictionary enumerator by removing items while enumerating.
also consider that order in which key pairs appear is not explicitly set in specification, so you may not rely on it - even if it works now it may stop working in a next version of framework. Thus you have also to decide what does "first 3" means before creating a list of elements to delete.
To remove an item in a dictionary, use the Remove() method. For example:
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
dictionary.Add("1", new List<string());
dictionary.Remove("1");
The order dictionary elements are added is not maintained. However, if you want to delete the highest key, for example, do something like:
dictionary.Remove(dictionary.Keys.OrderBy().First());
If dic is a "simple" Dictionary, using LINQ you can create a new dictionary from the original and reassign it to dic, like this:
dic = dic.Skip(3).ToDictionary(kv => kv.Key, kv => kv.Value);
As pointed out by astander in a comment and in Habib's answer, the order of the dictionary items is undefined, so you might want to apply this technique on a SortedDictionary only.
In that case, you would need to create a new SortedDictionary from the LINQ result:
dic = new SortedDictionary<string, List<string>>(
dic.Skip(3).ToDictionary(kv => kv.Key, kv => kv.Value));

Add to Dictionary<string, string> using foreach

what is the best way to ensure that optionValue is always unique in the following scenario?
public Dictionary<string, string> Dict = new Dictionary<string, string>();
foreach (string optionKey in i.options.Keys)
{
string optionValue = i.options.Values.ToString();
Dict.Add(optionKey, optionValue);
}
EDIT: i.options contains a key and a value pair. I need to ensure that for each key the corresponding value is added to the dictionary
EDIT2: corrected order of Dict.Add(optionKey, optionValue)
Just test for it:
if(!Dict.ContainsKey(optionValue))
Dict.Add(optionValue, optionKey)
Based on your variable names it looks like you have key and value reversed though, if optionKey is your lookup key it should be:
Dict.Add(optionKey, optionValue);
A cursory browsing of the MSDN documentation reveals that you can use the obvious method ContainsKey(string) to check to see if a dictionary contains a certain key.
In a Dictionary all keys are unique. If you want to prevent an exception when adding entries to the Dictionary, use
if (!Dict.ContainsKey(optionKey)) {
Dict.Add(optionKey, optionValue);
} else {
Debug.Print("Key '"+optionKey+"' already exists");
}
Depends how you want to handle duplicates.
E.g "last one wins"
foreach(...)
{
// Will overwrite an existing key
Dict[optionValue] = optionKey;
}
"First one wins":
foreach(...)
{
if (!Dict.ContainsKey(optionValue)) Dict.Add(optionValue, optionKey);
}
public Dictionary<string, string> Dict = new Dictionary<string, string>();
foreach (string optionKey in i.options.Keys)
{
string optionValue = i.options.Values.ToString();
if(!Dict.ContainsValue(optionValue))
Dict.Add(optionValue, optionKey);
}
See
http://msdn.microsoft.com/en-us/library/kw5aaea4(v=vs.100).aspx
If you are just worried about exceptions, then just use the item property:
Dict[optionValue] = optionKey;
MSDN: If the specified key is not found, a get operation throws a KeyNotFoundException, and a set operation creates a new element with the specified key.
Or if you really want to do the check, use the ContainsKey method to check
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
Other folks have been suggesting that you simply test to see if the key exists, and skip adding if it does. However, this may lead to lost data. You should create a custom class or type and use that with your dictionary like so:
public Dictionary< Guid, CustomObjectOrType > Dict = new
Dictionary< Guid, CustomObjectOrType >();
This way you can ensure that each key is unique (a Guid) while preserving all option values and option keys.

Quick mass-updating a Dictionary

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

The order of elements in Dictionary

My question is about enumerating Dictionary elements
// Dictionary definition
private Dictionary<string, string> _Dictionary = new Dictionary<string, string>();
// add values using add
_Dictionary.Add("orange", "1");
_Dictionary.Add("apple", "4");
_Dictionary.Add("cucumber", "6");
// add values using []
_Dictionary["banana"] = 7;
_Dictionary["pineapple"] = 7;
// Now lets see how elements are returned by IEnumerator
foreach (KeyValuePair<string, string> kvp in _Dictionary)
{
Trace.Write(String.Format("{0}={1}", kvp.Key, kvp.Value));
}
In what order will be the elements enumerated? Can I force the order to be alphabetical?
The order of elements in a dictionary is non-deterministic. The notion of order simply is not defined for hashtables. So don't rely on enumerating in the same order as elements were added to the dictionary. That's not guaranteed.
Quote from the doc:
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.
You can always use SortedDictionary for that. Note that the dictionary is ordered by Key, by default, unless a comparer has been specified.
I'm skeptic regarding the use of OrderedDictionary for what you want since documentation says that:
The elements of an OrderedDictionary are not sorted by the key, unlike
the elements of a SortedDictionary class.
If you want the elements ordered, use a SortedDictionary. An ordinary hastable/dictionary is ordered only in some sense of the storage layout.
The items will be returned in the order that they happen to be stored physically in the dictionary, which depends on the hash code and the order the items were added. Thus the order will seem random, and as implementations change, you should never depend on the order staying the same.
You can order the items when enumerating them:
foreach (KeyValuePair<string, string> kvp in _Dictionary.OrderBy(k => k.Value)) {
...
}
In framework 2.0 you would first have to put the items in a list in order to sort them:
List<KeyValuePair<string, string>> items = new List<KeyValuePair<string, string>>(_Dictionary);
items.Sort(delegate(KeyValuePair<string, string> x, KeyValuePair<string, string> y) { return x.Value.CompareTo(y.Value); });
foreach (KeyValuePair<string,string> kvp in items) {
...
}
For an OrderedDictionary:
var _OrderedDictionary = new System.Collections.Specialized.OrderedDictionary();
_OrderedDictionary.Add("testKey1", "testValue1");
_OrderedDictionary.Add("testKey2", "testValue2");
_OrderedDictionary.Add("testKey3", "testValue3");
var k = _OrderedDictionary.Keys.GetEnumerator();
var v = _OrderedDictionary.Values.GetEnumerator();
while (k.MoveNext() && v.MoveNext()) {
var key = k.Current; var value = v.Current;
}
Items are returned in the order that they are added.
Associative arrays (aka, hash tables) are unordered, which means that the elements can be ordered in any way imaginable.
HOWEVER, you could fetch the array keys (only the keys), order that alphabetically (via a sort function) and then work on that.
I cannot give you a C# sample because I don't know the language, but this should be enough for you to go on yourself.

Categories

Resources