8
votes
\$\begingroup\$

Example 1

if (myList.ContainsKey(myKey))
{
    myList[myKey]++;
}
else
{
    myList.Add(myKey,1);
}

Example 2

Where(x => 
(myList.ContainsKey(x.Key) ? x.Value - myList[x.Key] : x.Value) > 

myList is Dictionary.

Is there any way or existing method of simplifying or normalizing the code?

Update

Now I've learned Python and came across defaultdict:

\$\endgroup\$
  • 1
    \$\begingroup\$ Are these two snippets supposed to be doing the same thing? \$\endgroup\$ – Jimmy Hoffa Aug 23 '11 at 23:18
  • \$\begingroup\$ @Jimmy Hoffa: if I'm reading the second snippet correctly, If myList does not contain x.Key, it will throw an exception at x.Value - myList[x.Key]. It is definitely not doing the same thing ...if I'm reading correctly. \$\endgroup\$ – IAbstract Aug 24 '11 at 22:48
  • \$\begingroup\$ @IAbstract yeah I know they're not though the second one wont except, I was asking if he meant them to be the same because the way they were presented I first thought he wanted us to pick one over the other, now I think he wants them both improved separately \$\endgroup\$ – Jimmy Hoffa Aug 24 '11 at 23:36
  • \$\begingroup\$ @Jimmy: ...yeah, I was reading backwards ... \$\endgroup\$ – IAbstract Aug 24 '11 at 23:44
  • \$\begingroup\$ @IAbstract: I can thank SO for making me fluent in the ternary operator, seeing it enough times there and realizing how much it can simplify the code in the right place :) \$\endgroup\$ – Jimmy Hoffa Aug 25 '11 at 0:07
7
votes
\$\begingroup\$

For example, you can write your own extenession method for this operation and use it everywhere. Something like this

public static void SetOrIncrement<K>(this Dictionary<K, int> dictionary, K key)
    {
        int value;
        if (dictionary.TryGetValue(key, out value))
        {
            dictionary[key] = value + 1;
        }
        else
        {
            dictionary[key] = 1;
        }
    }

And then just use it in the following way:

 myList.SetOrIncrement(myKey);
\$\endgroup\$
  • \$\begingroup\$ Why not make a SetOrIncrementByTwoUnlessGreaterThanTen method then as well? \$\endgroup\$ – Steven Jeuris Aug 24 '11 at 8:05
  • \$\begingroup\$ Don't over exaggerate. This is a very simple operation in original post.There is no need to solve the problem that doesn't exist. Event if this 'SetOrIncrementByTwoUnlessGreaterThanTen' is required to be a very often operation I see no reasons why not to do so. What are the other options? I'm very interested to hear. \$\endgroup\$ – Andrey Taptunov Aug 24 '11 at 8:10
  • \$\begingroup\$ See my more reusable suggestion in my answer. \$\endgroup\$ – Steven Jeuris Aug 24 '11 at 8:19
11
votes
\$\begingroup\$

Also an alternative:

if (!myList.ContainsKey(myKey))
{
    myList.Add(myKey, 0);
}
myList[myKey]++;
\$\endgroup\$
  • \$\begingroup\$ The first example by the OP doesn't always increment the value ...the value is incremented only if the key is within the dictionary. \$\endgroup\$ – IAbstract Aug 25 '11 at 10:46
  • 2
    \$\begingroup\$ The first example adds the default value of 1 for new objects. My example generates the same outcome. \$\endgroup\$ – Mattias Aug 26 '11 at 8:34
  • \$\begingroup\$ Just as an FYI, your alternative (logically, not necessarily physically) accesses myList either 2 or 3 times (1 read and either 1 or 2 writes) while the original will always have 1 read and 1 write. \$\endgroup\$ – Jesse C. Slicer Aug 29 '11 at 17:56
  • \$\begingroup\$ @Jesse: Actually, the original (first example) did 1-2 reads and 1 write (the post-increment operator triggers both a read and a write). Personally, I would recommend using the TryGetValue as shown in some of the other answers rather than ContainsKey. \$\endgroup\$ – Brian Reichle Aug 31 '11 at 8:50
  • \$\begingroup\$ For the sake of readability, i prefer mine or the example 1 from the original post. I can live with the extra reads ;) \$\endgroup\$ – Mattias Aug 31 '11 at 11:33
1
vote
\$\begingroup\$

Let's see, for

Where(x =>
(myList.ContainsKey(x.Key) ? x.Value - myList[x.Key] : x.Value) >

I could think...

public static int GetSubtractedValueForMatchingKey<T>(this KeyValuePair<T,int> target, Dictionary<T,int> dictionaryToFindMatchingKey)
{
  return dictionaryToFindMatchingKey.ContainsKey(target.Key) ? 
    (target.Value - dictionaryToFindMatchingKey[target.Key]) :
    target.Value;
}

then..

Where(x => x.GetSubtractedValueForMatchingKey(myList) >
\$\endgroup\$
1
vote
\$\begingroup\$

Example 1:

var value = 0;

//  value is treated as a reference type with the out modifier
if (myList.TryGetValue(myKey, out value))
{
    myList[myKey] = value++; // I like this over myList[myKey]++

    //  either return here       
}
//  or wrap this in the else clause
myList.Add(myKey, value);

Example 2: the Where method must return a bool

var value = -1;
var result = myList.Where(x => !myList.TryGetValue(myKey, out value))
                   .Select(x => value > -1 ? x.Value - value : x.Value);

I don't know what your values are, but I believe it is close enough to get you on the right track. It will compile but I haven't tested any further.

\$\endgroup\$
  • \$\begingroup\$ Just as a note in your example 1 - value is incremented, but the value that was in the dictionary is not incremented (if you actually did the return at the commented return here section). You would only get the updated value if you allowed the code to flow to the myList.Add(...) line. It would be different if value was a reference type, but in the code presented in the question it is a value type. \$\endgroup\$ – pstrjds Aug 31 '11 at 13:36
  • \$\begingroup\$ @pstrjds: true enough ...will fix. \$\endgroup\$ – IAbstract Aug 31 '11 at 14:09
0
votes
\$\begingroup\$

Just an idea ...

public static void UpdateOrAdd<TKey, TValue>(
    this Dictionary<TKey, TValue> source,
    TKey key, Func<TValue, TValue> updateValue, Func<TValue> initializeValue )
{
    TValue value;
    if ( source.TryGetValue( key, out value ) )
    {
        source[ key ] = updateValue( value );

    }
    else
    {
        source.Add( key, initializeValue() );            
    }
}

Could be used as a one-liner.

myList.UpdateOrAdd( myKey, v => v + 1, () => 1 );

A lambda is used for the initializer so that the initial object for dictionaries with reference types is only created once.


Similarly you could do the following for example 2.

public static TValue GetOrDefault<TKey, TValue>(
    this Dictionary<TKey, TValue> source,
    TKey key, TValue defaultValue )
{
    return source.ContainsKey( key ) ? source[ key ] : defaultValue;
}

To use like:

x.Value - myList.GetOrDefault( x.Key, 0 ) > ...
\$\endgroup\$
  • 2
    \$\begingroup\$ myList.SetOrCreate( myKey, myList[ myKey ] + 1, 1 ); This code is plain wrong. Evaluation of 2nd parameter will fail with KeyNotFoundException if there is no such key in a list. \$\endgroup\$ – Andrey Taptunov Aug 24 '11 at 8:34
  • \$\begingroup\$ @Andrei: You are right, probably solveable by using a lambda, but then the solution might get less interesting. \$\endgroup\$ – Steven Jeuris Aug 24 '11 at 8:46
  • \$\begingroup\$ Updated the answer accordingly, it's not too bad ... \$\endgroup\$ – Steven Jeuris Aug 24 '11 at 8:49
  • \$\begingroup\$ Now you access a dictionary 3 times in for a given key in else branch versus 2 times in the original post. Still O(1) operation in average case but in case of collision you will traverse underlying chain 1.5 times more. Perfromance is affected but should not. \$\endgroup\$ – Andrey Taptunov Aug 24 '11 at 8:57
  • \$\begingroup\$ @Andrei: Interesting, but you know what they say about premature optimization. ;p However, by using TryGetValue this could be optimized again. \$\endgroup\$ – Steven Jeuris Aug 24 '11 at 9:14
0
votes
\$\begingroup\$

myList is Dictionary

I don't write C# and don't really know what a Dictionary construct is, but I think what you're looking at is a Map. Each word is the key element, as it must be unique and the value is the times the word is met.

So in Java that would be like this:

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author c00kiemon5ter
 */
public class MapCountDict {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        /*
         * A testing dictioary
         */
        String[] dictionary = new String[]{ "foo", "foo", "foo", "bar", "bar", "yow" };

        /* 
         * The collection to hold the times each word is found
         * 
         * Each word is unique in the collection. The word is the key.
         * The value is the times the word is met when going through
         * the "dictionary".
         */
        Map<String, Integer> occurances = new  HashMap<String, Integer>();

        /*
         * Run through the dictionary, adding up the times each word is met.
         */
        for (String word : dictionary) {
            Integer value = occurances.get(word);
            occurances.put(word, (value == null) ? 1 : value+1);
        }

        /*
         * Print the results
         */
        for (String word : occurances.keySet()) {
            System.out.printf("%s\t%d\n", word, occurances.get(word));
        }
    }
}

Results:

yow   1
foo   3
bar   2

Converting your Dictionary to a Map cause some overhead, but depending on what you'll be doing, it might also help you with other things.

Hope that helps a bit.

\$\endgroup\$
  • 1
    \$\begingroup\$ "Converting your Dictionary to a Map cause some overhead, but depending on what you'll be doing, it might also help you with other things." Dictionary is a map. \$\endgroup\$ – sepp2k Aug 31 '11 at 15:02
0
votes
\$\begingroup\$

In terms of readability, my vote goes for the ternary operator:

myList[myKey]=(myList.ContainsKey(myKey))?myList[myKey]+=1:1;

Does, what it should. Is simple to read, and was just invented for that purpose. I wonder, why nobody else came up with it.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.