Click here to Skip to main content
15,881,789 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Is there any way to add new value into existing dictionary, using it's key parameter for check up?
Posted
Updated 9-Apr-15 5:44am
v2

Please see our constructive discussion with Sascha Lefévre in comments to Solution 1. It is not yet quite comprehensive, as not all variants of modification by key are accessible to the user. Also, exception information is not informative. It is important to remember that key and value types may be not well presentable as strings.

As I was the one who suggested most of improvements, but it wasn't enough, let me summarize it on more general solution:
C#
using System.Collections.Generic;

public class DictionaryWrapper<KEY, VALUE> {

    public enum ValueModificationResult {
        Success,
        KeyNotFound,
        NoValueChangeNeeded,
    }

    Dictionary<KEY, VALUE> dictionary = new Dictionary<KEY, VALUE>();

    public ValueModificationResult ModifyExceptionless(KEY key, VALUE value) {
        VALUE oldValue;
        if (dictionary.TryGetValue(key, out oldValue)) {
            if (value.Equals(oldValue))
                return ValueModificationResult.NoValueChangeNeeded;
            dictionary[key] = value;
            return ValueModificationResult.Success;
        } else
            return ValueModificationResult.KeyNotFound;
    } //ModifyExceptionless

    // variant:
    public bool ModifyCombined(KEY key, VALUE value) {
        VALUE oldValue;
        if (dictionary.TryGetValue(key, out oldValue)) {
            bool result = !value.Equals(oldValue);
            if (result)
                dictionary[key] = value;
            return result;
        } else
            throw new ValueModificationException<KEY, VALUE>(key, value);
    } //ModifyCombined

    public ValueModificationResult AddOrModify(KEY key, VALUE value) {
        var result = ModifyExceptionless(key, value);
        if (result == ValueModificationResult.KeyNotFound) {
            dictionary.Add(key, value);
            return ValueModificationResult.Success;
        } //if
        return result;
    } //AddOrModif

    // this implicitely exposes the rest of Dictionary functionality:
    public static implicit operator Dictionary<KEY, VALUE>(DictionaryWrapper<KEY, VALUE> wrapper)
       { return wrapper.dictionary; }

    // alternatively or additionally, wrap some Dictionary functionality
    // ...

} //class DictionaryWrapper


C#
public class ValueModificationException<KEY, VALUE> : System.ApplicationException {
    internal ValueModificationException(KEY key, VALUE value) {
        this.Key = key; this.Value = value;
    } //ValueModificationException
    public KEY Key { get; private set; }
    public VALUE Value { get; private set; }
} //class ValueModificationException


Usage:
C#
class UsageSample {

    static void Test() {
        DictionaryWrapper<string, int> wrapper = new DictionaryWrapper<string,int>();
        Dictionary<string, int> dictionary = wrapper;
        dictionary.Add("1", 1);
        var result = wrapper.AddOrModify("1", 2); //Success
        ///...
    } //Test

} //class UsageSample


Note the use of private setters of exception properties (read-only from outside class) and internal constructor (try not to give more access then required). Also note some benefits of the ModifyExceptionless variant of the Modify method: it is more suitable for use in AddOrModify.

—SA
 
Share this answer
 
v3
Comments
Sascha Lefèvre 9-Apr-15 14:37pm    
My 5.

One suggestion though: In ModifyExceptionless() and ModifyCombined() you let the dictionary look up the key twice, you could use TryGetValue() instead.

And one question: Is there a specific reason why you expose the rest of the dictionaries functionality with an implicit operator instead of deriving your class from dictionary or is it just personal preference?
Sergey Alexandrovich Kryukov 9-Apr-15 14:54pm    
Thank you, Sascha.
I though about doubled key lookup already. Thank your very much for the suggestion; I will try to improve it a bit later already improved the code the way you advised.

Implicit operator thing does not have principle character: I was just thinking how to get away with the class with apparently incomplete functionality, focusing only on the requested functionality but not leaving the impression that I left the reader with something totally unusable.

In other words, it was just my way to say: "ah, dictionary-mictionary..." :-). I explained this fundamental feature, which is called m-reduplication (and also shm-reduplication as in dictionary-shmictionary") in my last 1st of April article.

Look! I think I failed to invite me to read my 1st of April article. Sorry, that was wrong.

I would like to use the occasion to invite your (and everyone else, of course) to see my new 1 of April publication and have some fun:
Some Programming Approaches to "Neuro-Linguistic Programming".
Participation in this game in Comments and Discussions is especially encouraged. Many already enjoyed it, I hope.

By the way, if, by any chance, you are the same very Prof. Lefévre, the co-inventor of that psychotropic weapon, the one who later escaped from Fantomas (I was always tempted but afraid to ask how have you been since then; hope you know what I'm talking about), it would be especially interesting to learn about novel mental-shaping technique in programming.

Thank you.
—SA

P.S.: my answer to your question was detailed enough, wasn't it? :-)
Sascha Lefèvre 9-Apr-15 15:01pm    
lol :-)
Sergey Alexandrovich Kryukov 9-Apr-15 15:04pm    
Look, I added a new paragraph above, before "Thank you".
—SA
Sascha Lefèvre 9-Apr-15 15:33pm    
Dear Sergey Alexandrovich, thank you for asking! As you might imagine, my age brings some discomfort but thankfully I have been able to apply my neuroscientific discoveries to myself some centuries ago and so I'm still capable of expanding on my works. I have read your article on Neuro-Linguistic Programming with interest and — though I am not able to go into much detail at this point, I hope you will understand this — I can tell you that you are on to something there and maybe I can share my discoveries with you some time in the future. Best Regards, Prof. Dr. Lefebvre

PS: Yes ;)
Of course:
C#
// this will work regardless if "someKey" was previously present in the dictionary or not:
yourDictionary[someKey] = newValue;


// if you want to ensure that "someKey" actually is already present:
if (yourDictionary.Contains(someKey))
   yourDictionary[someKey] = newValue;
else
   // throw an Exception or something


// if you want to ensure that "someKey" is NOT already present:
yourDictionary.Add(someKey, newValue);
// (will throw an Exception otherwise)


Edit:

You could create an extension method for the "second case" above:
C#
using System;
using System.Collections.Generic;

namespace MyExtensionClasses
{
  public static class MyDictionaryExtension
  {
    // will add or update
    // returns true if the key-value-pair was added or updated
    // return false if the new value was equal to the already existing value
    public static bool AddOrUpdate<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
    {
        bool addedOrUpdated = false;
        TValue oldValue;
        if (!dict.TryGetValue(key, out oldValue) || !value.Equals(oldValue))
        {
            dict[key] = value;
            addedOrUpdated = true;
        }
        return addedOrUpdated;
    }

    // will only update a value if the key already exists
    // and throw an exception otherwise
    public static void UpdateExisting<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
    {
        if (dict.ContainsKey(key))
            dict[key] = value;
        else
            throw new InvalidOperationException("Can't update because key not found in dictionary: " + key.ToString());
    }
  }
}

You can just copy the code above into a new code file, insert a using MyExtensionClasses; at the top of your code files where you want to use it and then use the methods as if they were regular methods of the Dictionary-class.
 
Share this answer
 
v5
Comments
Sergey Alexandrovich Kryukov 9-Apr-15 11:50am    
Up-voted, but... not quite clear. It would help if you wrote just a functions with parameters, which would be self-explained.

More importantly, "throw an exception" is wrong approach. Write approaches are: 1) do nothing; 2) add to the dictionary unconditionally and let the dictionary itself throw the exception. Why creating superfluous thunk between your and dictionary code?

—SA
Sascha Lefèvre 9-Apr-15 12:08pm    
Thank you, Sergey!

But in the case "I want to update a value in the dictionary and ensure that there actually already is a value with the same key" (that's how I interpreted the question) the Dictionary doesn't offer a method that would fail if there is no such key present yet. That's why constructed that middle part in the code-block.

By your first suggestion do you mean the following?:

void UpdateExistingValueOrFail<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
{
   if (dict.Contains(key))
      dict[key] = value;
   else
      throw new InvalidOperationException("can't update because key not found");
}
Sergey Alexandrovich Kryukov 9-Apr-15 12:21pm    
Ah, you are right, I missed it.

Anyway, if you show the function ModifyKey(string key, string newValue); it would be clear. By they way, you could simply return false to indicate absence of the key (or, better, "no changes have been done", then you would need to do nothing also when old value is the same as new value). Depending on intent of the use, throwing exception would also be a choice.

—SA
Sascha Lefèvre 9-Apr-15 12:52pm    
Alright, I updated my solution. I like the idea of returning "no changes have been done" - but that would require to restrict TValue to reference types.
/Sascha
Sergey Alexandrovich Kryukov 9-Apr-15 13:07pm    
No, it won't. Everything remains the same. You can always compare two values using Object.Equals and act accordingly. It will be semantic comparison based on overridden method Equals in each value type, which always can be called in type-agnostic call of a generic class/method.
—SA
XML
Dictionary<string, string> dictionary = new Dictionary<string, string>();
            
//Check if "Key" is already present in dictionary
if (!dictionary.ContainsKey("Key"))
            {
                dictionary["Key"] = "Value" ;

            }
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 9-Apr-15 11:45am    
Will throw exception or do nothing. Useless because "Key" and "Value" are hard-coded.
Always test your solutions before posting. Please...
—SA
ConnectingKamlesh 10-Apr-15 2:45am    
SA, it's not useless, "Key" here is the key which needs to be matched and needs to be replaced by the user, it seems you just copy and paste the answers and don't read or try to understand it. This is the simplest way to add new value into existing dictionary<string, string="">, using it's key parameter for check up.
Sergey Alexandrovich Kryukov 10-Apr-15 11:32am    
I did not copy and paste anything. This is just too bad style answering the question. Naive readers may think that you suggest not to replace hard-coded key and value, but to hard-code then. And you cannot add a key-value pair on already contained key. This is you who need to copy and paste your own "solution" to real code and check up if it works.
—SA
ConnectingKamlesh 13-Apr-15 3:22am    
This code is from a working program, you just cannot say anyone's solution/answers as "useless" because you think you are genious. Please check on your language before replying, It should not hurt.
Sergey Alexandrovich Kryukov 13-Apr-15 10:01am    
I don't even understand what you are talking about.
I correctly explained to you why your code is wrong. Please keep to the facts and logic not move to personal issues and accusations; in this community, this is not welcome, as well as rude behavior.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900