Weird performance results using Dictionary<> - c#

It seems that Dictionary<,> performance is affected by the size of the item being stored (which seems bizarre).
Here's my simple class:
public class MyObject
{
public Guid Key { get; set; }
}
And two simple tests:
private long _Iterations = 1000000;
[TestMethod]
public void ShouldTestDefaultConstructorPerformance()
{
for (var i = 0; i < _Iterations; i++)
{
var obj = new MyObject() { Key = Guid.NewGuid() };
}
}
[TestMethod]
public void ShouldTestDefaultGuidDictionaryPerformance()
{
var dict = new Dictionary<Guid, MyObject>();
for (var i = 0; i < _Iterations; i++)
{
var obj = new MyObject() { Key = Guid.NewGuid() };
dict.Add(obj.Key, obj);
}
}
Initially I get the following timings:
ShouldTestDefaultConstructorPerformance : 00:00:00.580
ShouldTestDefaultGuidDictionaryPerformance : 00:00:01.238
Now, I'll change MyObject class:
public class MyObject
{
public Guid Key { get; set; }
private Dictionary<string, string> _Property0 = new Dictionary<string, string>();
private Dictionary<string, string> _Property1 = new Dictionary<string, string>();
private Dictionary<string, string> _Property2 = new Dictionary<string, string>();
private Dictionary<string, string> _Property3 = new Dictionary<string, string>();
private Dictionary<string, string> _Property4 = new Dictionary<string, string>();
private Dictionary<string, string> _Property5 = new Dictionary<string, string>();
private Dictionary<string, string> _Property6 = new Dictionary<string, string>();
private Dictionary<string, string> _Property7 = new Dictionary<string, string>();
private Dictionary<string, string> _Property8 = new Dictionary<string, string>();
private Dictionary<string, string> _Property9 = new Dictionary<string, string>();
}
And run the tests again:
ShouldTestDefaultConstructorPerformance : 00:00:01.333
ShouldTestDefaultGuidDictionaryPerformance : 00:00:07.556
In the second test, the object construction takes 1.72x longer, but adding to the Dictionary takes 6.11x longer. I expected the tests to take longer, but why does the Dictionary take so much longer to add larger objects?

I think people need to read questions more carefully instead of rushing to post an answer. If you look at his sample code carefully (BOTH tests), the difference between having a MyObject with a Guid and MyObject with a Guid and 10 Dict's is under a second (object construction) for his loop. However the add dictionary accounts for at least 5 more seconds.

I think my answer would be: use a profiler and work out which bit is actually taking longer.
That'd probably highlight the instantiation. Maybe :)

I would think that var obj = new MyObject() { Key = Guid.NewGuid() }; this line actually takes much longer and not Add() of dictionary. Did you make measuring inside methods provided?

Each object you add to the dictionary is given a special unique identifier to speed up its searching and retrieval in memory. This special unique identifier (called a hash) is computed by analysing the entire content of the object. The larger the object, the slower it will be to compute the hash.
If you are interested in the fine details of how it works, check out this example from a university course: http://www.ccs.neu.edu/home/sbratus/com1101/hash-dict.html

Related

C# Dictionary loses keys and values

i have a problem with updating keys and values in dictionary, dictionary loses data everytime when new StreamReader runs on. I wanted StreamReader to read list and when it reads second path keys and values in dictionary are already lost. I would be greateful for help.
class TT_connect
{
public Dictionary<string, double> s_c = new Dictionary<string, double>();
public TT_connect(List<string> tempAS){
Dictionary<string, double> s_a = new Dictionary<string, double>();
foreach(string a in tempAS)
{
using (var s = new StreamReader(a))
{
while (!s.EndOfStream)
{
var l_a = s.ReadLine();
var l_b = l_a.Split(';');
if (s_a.Keys.Contains(l_b[0]))
{
double.TryParse(l_b[1], out double l1);
s_a[l_b[0]] += l1;
}
if (!s_a.Keys.Contains(l_b[0]))
{
double.TryParse(l_b[1], out double l2);
s_a.Add(l_b[0], l2);
}
}
}
}
foreach(KeyValuePair<string,double> s in s_a)
{
s_c.Add(s.Key, s.Value);
}
}
}
Based on Roberts comments i have tried to clean up the implementation a bit.
class TT_connect
{
private string _fileLocation;
public Dictionary<string, double> dict;
public TT_connect(string fileLocation)
{
dict = new Dictionary<string, double>();
_fileLocation = fileLocation;
}
public void FillDictionary()
{
using (var s = new StreamReader(_fileLocation))
{
int lineCount = 0;
while (!s.EndOfStream)
{
string line = s.ReadLine();
lineCount++;
string key = line.Split(';')[0];
string stringValue = line.Split(';')[1];
if (!Double.TryParse(stringValue, out double val))
throw new Exception($"Can't pass value on line: {lineCount}");
if (dict.Keys.Contains(key))
{
dict[key] += val;
}
else
{
dict.Add(key, val);
}
}
}
}
}
Here's what I recommend:
Instantiate your class's dictionary field in the class constructor. That's all you should do in the constructor. Or, go ahead and let it instantiate automatically, as you do now, and forego the constructor entirely.
Provide an Add method that replaces the code in your previous constructor. Use it to do the work of adding your dictionary/stream items. You won't need another dictionary; just add the items to your class's dictionary, directly.
Your current logic does a bit too much in the constructor, and overall there is more logic in your class than you actually need to get the job done.

Writing into nested Dictionary in Unity3D

Can I not write values into my nested dictionary directly?
It would be nice if I could access it like this:
public Dictionary<string, Dictionary<string, Dictionary<string, int>>> planets =
new Dictionary<string, Dictionary<string, Dictionary<string, int>>>();
planets[Planet.CharacterId]["MetalMine"]["Level"] = 0;
But I'm getting:
KeyNotFoundException: The given key was not present in the dictionary.
Does this mean I got to insert my Keys after each other?
Does this mean I got to insert my Keys after each other?
Yes, you need to initialize each in order:
planets[Planet.CharacterId] = new Dictionary<string, Dictionary<string, int>>();
planets[Planet.CharacterId]["MetalMine"] = new Dictionary<string, int>();
planets[Planet.CharacterId]["MetalMine"]["Level"] = 0;
You could use collection initializer syntax here, but that won't make stuff much more readable nor maintainable.
Instead of a dictionary of dicionaries of dictionaries you seem to be better off using a class:
public class Planet
{
public List<Mine> Mines { get; set; }
}
public class Mine
{
public string Type { get; set; }
public int Level { get; set; }
}
var planets = new Dictionary<string, Planet>();
planets[Planet.CharacterId] = new Planet
{
Mines = new List<Mine>
{
new Mine
{
Type = "Metal",
Level = 0
}
};
}
It's may be helpful or Nested dictionary alternative.
Create Sample.cs script and test it.
public Dictionary<string,Tuple<string,string,string,int>> _planets = new Dictionary<string, Tuple<string,string, string, int>>();
void Start()
{
string myKey = string.Concat("1","MetalMine","Level");
if(!_planets.ContainsKey(myKey))
{
_planets.Add(myKey,Tuple.Create("1","MetalMine","Level",0));
}
Debug.Log("_planets mykey "+myKey+" ==> "+_planets[myKey].Item4);
}

Converting an anonymous object's properties and values to a Dictionary

I am creating a library for an existing API. I currently have QueryParameter classes for each request class. The QueryParameter classes are simple but they do vary (not all requests take the same query parameters).
Here is an example of a QueryParameter class:
public class ApiRequestAQueryParameters
{
public string Name { get; set; }
public int Start { get; set; }
public int Stop { get; set; }
}
I am interested in a way to convert a class like this into a Dictionary that I can feed to our Web client. I am hoping to have a reusable method like:
private Dictionary<string, string> GenerateQueryParameters(object queryParametersObject)
{
// perform conversion
}
This way I won't have to pull out the QueryParameter properties for each request (there will be dozens of requests)
The reason that I am using QueryParameter classes instead of making QueryParameter a Dictionary property of each API request class is to be developer friendly. I want to make it so that others can build these API requests by looking at the classes.
There are 2 ways: 1) use reflection and 2) serialize to json and back.
Here is the 1st method:
private Dictionary<string, string> GenerateQueryParameters(object queryParametersObject)
{
var res = new Dictionary<string, string>();
var props = queryParametersObject.GetType().GetProperties();
foreach (var prop in props)
{
res[prop.Name] = prop.GetValue(queryParametersObject).ToString();
}
return res;
}
You can do something like this:
private Dictionary<string, string> GenerateQueryParameters(object queryParameters)
{
var startStop = new StartStop() { Start = queryParameters.Start, Stop = queryParameters.Stop};
var result = new Dictionary<string, string>();
result.Add(queryParameters.Name, startStop);
return result;
}
public class StartStop
{
public int Start { get; set; }
public int Stop { get; set; }
}
This may be the perfect case to utilize ExpandoObjects. An ExpandoObject is a dynamic type, whose properties can be created at run time. ExpandoObject implements IDictionary < string, object > so it's easy to convert to a Dictionary < string, object > .
In the example below, an ExpandoObject is created and converted to a Dictionary < string, object > and then converted to a Dictionary < string, string >.
dynamic apiVar = new ExpandoObject();
apiVar.Name = "Test";
apiVar.Start = 1;
apiVar.Stop = 2;
var iDict = (IDictionary<string, object>) apiVar;
/* if you can utilize a Dictionary<string, object> */
var objectDict = iDict.ToDictionary(i => i.Key, i => i.Value);
/* if you need a Dictionary<string, string> */
var stringDict = iDict.ToDictionary( i=>i.Key, i=> i.Value.ToString());
There are also different ways of setting properties on an ExpandoObject. Below is an example of setting a property by a variable name.
dynamic apiVar = new ExpandoObject();
var propertyName = "Name";
apiVar[propertyName] = "Test";
propertyName = "Start";
apiVar[propertyName] = 1;
propertyName = "Stop";
apiVar[propertyName] = 2;
I always reuse the RouteValueDictionary class for this. It has a constructor that accepts any object and the class itself implements IDictionary.
It's available in the System.Web dll
private Dictionary<string, string> GenerateQueryParameters(object queryParametersObject)
{
return new RouteValueDictionary(queryParametersObject).ToDictionary(d => d.Key, d => Convert.ToString(d.Value));
}

Creating a custom list class in C#

I want to create a class that is a Custom List. So I have done
public class Set1 : List<Dictionary<string, string>>
{
public Set1() : base(List<Dictionary<string, string>>)
{
List<Dictionary<string, string>> mySet = new List<Dictionary<string, string>>()
{
new Dictionary<string, string>()
{
{"first_name","John"},
},
new Dictionary<string, string>()
{
{"last_name","Smith"},
},
};
base(mySet);
}
}
But this does not compile. What am I doing wrong please? Thanks in advance.
You can't call a base/alternate constructor from within the method in C# like you can in some other languages.
However, you don't need to call the base constructor in this case - you can just do:
public Set1()
{
this.Add(
new Dictionary<string, string>()
{
{"first_name","John"},
}
);
this.Add(
new Dictionary<string, string>()
{
{"last_name","Smith"},
}
);
}
If you really want to call the base constructor, though, you'll have to inline the list creation in the declaration:
public Set1()
: base( new List<Dictionary<string, string>>
{
new Dictionary<string, string>()
{
{"first_name","John"},
},
new Dictionary<string, string>()
{
{"last_name","Smith"},
}
}
)
{
// nothing more to do here
}
but that creates a list, only to have the constructor copy the items into the list, increasing your memory usage for a short time.
Here is the code you're looking for
new Dictionary<string, string>() {
{"first_name","John"}, {"last_name","Smith"},
}.
You don't have any need to inherit from List here. What you wanted was an instance of some collection. A class is a general template for data and behaviour, not something you define to hold the specific information for John.
Even better, create a class for the apprioriate thing (a person), and create an instance of a List<Person>
public class Person
{
public string Forename {get;set;}
public string Surname {get;set;}
}
///
var people = new List<Person>() { new Person("John", "Smith") };

.NET Dictionary as a Property

Can someone point me out to some C# code examples or provide some code, where a Dictionary has been used as a property for a Class.
The examples I have seen so far don't cover all the aspects viz how to declare the dictionary as property, add, remove, and retrieve the elements from the dictionary.
Here's a quick example
class Example {
private Dictionary<int,string> _map;
public Dictionary<int,string> Map { get { return _map; } }
public Example() { _map = new Dictionary<int,string>(); }
}
Some use cases
var e = new Example();
e.Map[42] = "The Answer";
sample code:
public class MyClass
{
public MyClass()
{
TheDictionary = new Dictionary<int, string>();
}
// private setter so no-one can change the dictionary itself
// so create it in the constructor
public IDictionary<int, string> TheDictionary { get; private set; }
}
sample usage:
MyClass mc = new MyClass();
mc.TheDictionary.Add(1, "one");
mc.TheDictionary.Add(2, "two");
mc.TheDictionary.Add(3, "three");
Console.WriteLine(mc.TheDictionary[2]);
EDIT
When you use C# version 6 or later, you can also use this:
public class MyClass
{
// you don't need a constructor for this feature
// no (public) setter so no-one can change the dictionary itself
// it is set when creating a new instance of MyClass
public IDictionary<int, string> TheDictionary { get; } = new Dictionary<int, string>();
}
You could also look into indexers. (official MSDN documentation here)
class MyClass
{
private Dictionary<string, string> data = new Dictionary<string, string>();
public MyClass()
{
data.Add("Turing, Alan", "Alan Mathison Turing, OBE, FRS (pronounced /ˈtjʊ(ə)rɪŋ/) (23 June, 1912 – 7 June, 1954) was a British mathematician, logician, cryptanalyst and computer scientist.")
//Courtesy of [Wikipedia][3]. Used without permission
}
public string this [string index]
{
get
{
return data[index];
}
}
}
Then, once you have populated the dictionary internally, you can access it's information by going
MyClass myExample = new MyClass();
string turingBio = myExample["Turing, Alan"];
EDIT
Obviously, this has to be used carefully, because MyClass is NOT a dictionary, and you cannot use any dictionary methods on it unless you implement them for the wrapper class. But indexers are a great tool in certain situations.
In order to ensure the encapsulation is correct and the dictionary cannot be updated outside the class using Add or the form ExampleDictionary[1]= "test", use IReadOnlyDictionary.
public class Example
{
private Dictionary<int, string> exampleDictionary;
public Example()
{
exampleDictionary = new Dictionary<int, string>();
}
public IReadOnlyDictionary<int, string> ExampleDictionary
{
get { return (IReadOnlyDictionary<int, string>)exampleDictionary; }
}
}
The following code will not work, which is not the case if IDictionary is used:
var example = new Example();
example.ExampleDictionary[1] = test;
Another example of using a dictionary as a static property with only the get accessor:
private static Dictionary <string, string> dict = new Dictionary <string,string>(){
{"Design Matrix", "Design Case"},
{"N/A", "Other"}
};
public static Dictionary <string, string> Dict
{
get { return dict}
}
This structure can be used to replace values.
An example...
public class Example
{
public Dictionary<Int32, String> DictionaryProperty
{
get; set;
}
public Example()
{
DictionaryProperty = new Dictionary<int, string>();
}
}
public class MainForm
{
public MainForm()
{
Example e = new Example();
e.DictionaryProperty.Add(1, "Hello");
e.DictionaryProperty.Remove(1);
}
}
Since .net 4.6 you can also define a Dictionary like this:
private Dictionary<string,int> Values => new Dictionary<string, int>()
{
{ "Value_1", 1},
{ "Value_2", 2},
{ "Value_3", 3},
};
It's called Expression-bodied members!
You mean like a property bag ?
http://www.codeproject.com/KB/recipes/propertybag.aspx

Categories

Resources