c# dictionary select value from key - c#

I've been searching through here and I realize that similar questions have been asked before, and I've gone over several, but what seems to be correct doesn't seem to be working for.
I have the following method which pulls a set of key value pairs in a DataSet gathered from a SQL query.
public static Dictionary<string, string> LoadConfiguration()
{
DataSet sqlResults = data.GetSettings();
Dictionary<string, string> dict =
new Dictionary<String, String>();
foreach (DataRow dr in sqlResults.Tables[0].Rows)
{
dict.Add(
dr.Field<string>("key"), dr.Field<string>("value")
);
}
return dict;
}
It's as simple as it gets as far as I can see, but I've never actually worked with a dictionary before as I'm relatively new to any kind of real programming.
I know that my Dictionary has the expected data, because if I iterate through it with a foreach, it gives me the expected results
foreach (KeyValuePair<string, string> i in MyStuff.Configuration.LoadConfiguration())
{
Console.WriteLine("Key = " + i.Key + " Value = " + i.Value);
}
which gives me the following which is all I've implemented so far
Key = EnableLdap Value = false
Key = LdapPath Value = LDAP://DC=some,DC=domain,DC=com
Key = SessionTimeout Value = 60
But I only want to select a specific value from a key named EnableLdap for example
My understanding is that both the following methods would be correct. But when I try this way, I get a KeyNotFoundException
Dictionary<string,string> dict = MyStuff.Configuration.LoadConfiguration();
Console.WriteLine(dict["EnableLdap"]);
If I try this I get a [InvalidOperationException: Sequence contains no matching element]
Dictionary<string,string> dict = MyStuff.Configuration.LoadConfiguration();
Console.WriteLine(dict.Single(s => s.Key == "EnableLdap").Value);
And if I try this I just get nothing
string value = "";
if (dict.TryGetValue("EnableLdap", out value))
{
dict["EnableLdap"] = value;
Console.WriteLine(value);
}
I'm pretty certain I'm missing something simple here and the answer will result in a facepalm
SOLUTION:
I got caught by trailing spaces as was suggested a few times in the comments. The solution was to simply add some trimming to my row values when adding them to my Dictionary.
public static Dictionary<string, string> LoadConfiguration()
{
DataSet sqlResults = data.GetSettings();
Dictionary<string, string> dict =
new Dictionary<String, String>();
foreach (DataRow dr in sqlResults.Tables[0].Rows)
{
dict.Add(
dr.Field<string>("key").Trim(), dr.Field<string>("value").Trim()
);
}
return dict;
}

It is one of these 2 issues.
The key does not exist in the dictionary, this could be due to a spelling mistake or even a leading/trailing space or something of that nature.
The key exists but is cased differently than you think it is.
For option 2 you can ensure that casing is not an issue by providing a StringComparer to the dictionary as an argument in the constructor.
Dictionary<string, string> dict = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
The above code snippet will ensure that the dictionary creates the hash for each key based on the ordinal case insensitive representation of the string key. This will allow for the following example to pass:
dict["enableldap"] = "true";
Console.WriteLine(dict["EnableLdap"]);
See StringComparer for more options.

My understanding is that both the following methods would be correct. But when I try this way, I get a KeyNotFoundException
It seems that your dictionary doesn't have that key. Keep in mind that dictionaries are key-sensitive you can check if a key exist by using this method:
Console.WriteLine("Exist key "+ dict.ContainsKey("EnableLdap"));
If I try this I get a [InvalidOperationException: Sequence contains no matching element]
Dictionary<string,string> dict = MyStuff.Configuration.LoadConfiguration();
Console.WriteLine(dict.Single(s => s.Key == "EnableLdap").Value);
The linQ method .Single expects to find a value. If no value is found that Exception will be thrown. You should be using .SingleOrDefault if you don't want that exception, but beware of nulls.
And if I try this I just get nothing.
TryGetValue doesn't throw any exceptions. It just tries.
I'd suggest you to add a format for your keys either uppercased or lowercased, when you're creating the dictionary.
foreach (DataRow dr in sqlResults.Tables[0].Rows)
{
dict.Add(
dr.Field<string>("key").ToUpperCase(), dr.Field<string>("value")
);
}
and then you can query it like this:
if(dict.ContainsKey("ENABLELDAP"))
{
string value = dict["ENABLELDAP"];
}

Related

get string array out of Dictionary<int, string[]>

this is my code
pritvate static Dictionary<int, string[]> _list = new Dictionary<int, string[]>();
how can i get the string[] out of this?
I have tried this and a lot more:
string[] s = _list.Values;
but it is all not working.
please help
If you want all string arrays for all keys merged into a single array, you can use LINQ's .SelectMany(...):
var strings = _list.Values.SelectMany(v => v).ToArray()
Reading your question again, I wonder if you're asking how to access a value for a single key. So, if you want the string array for a single key you can simply use the indexer:
var value = _list["keyname"];
But that will cause an exception if the key doesn't exist. If you're not sure that the key exists, you can use .TryGetValue(...):
string[] value;
if (_list.TryGetValue("keyname", out value))
{
// value was found
}
else
{
// value wasn't found
}

C# Data structure to sort against specific values

I have an output of a method that provides two key pieces of data per result.
Eg: 20160503 and nzdusd.
How can I store this in a dictionary and the sort against either one?
I want to be able to sort against key or value but can't get past adding the data!
Is there another data structure better suited?
Previously I tried simply calling Add()
But got an ArgumentException with message, An item with the same key has already been added..
Dictionary<string, string> missingDays = new Dictionary<string, string>();
// Some logic
missingDays.Add(formattedDate, fxPair); // Exception here
foreach (var missingDay in missingDays)
{
Console.WriteLine(missingDay);
}
A dictionary must have unique key values. In this case the formattedDate variable is being assigned the same value more than once, which causes an exception the second time you try to add an entry to the dictionary with the same formattedDate value.
You can use a Tuple<string, string> inside a list (List<Tuple<string, string>>) to store the values, and then use the LINQ method OrderBy() to sort the list.
var missingDays = new List<Tuple<string, string>>();
missingDays.Add(Tuple.Create("exampleFormattedDate", "exampleFxPair"));
foreach (var missingDay in missingDays.OrderBy(md => md.Item1))
{
Console.WriteLine(missingDay);
}

Cast all keys in dictionary to uppercase

This is probably a very simple question but google has let me down sofar and keeps pointing me towards python solutions.
I have a webpage where applciations/users can supply querystringparameters.To Retrieve the querystring parameters I use the following code:
IDictionary<string, string> qStrings = HtmlPage.Document.QueryString;
to check the presence of a specified key, I use the following code:
if (!String.IsNullOrEmpty(qStrings["PARAM1"]))
{}
Knowing our users, i'm expecting them to give parameterkeys as follows: "Param1", "param1", "pArAm1"
How can simply cast every key in a dictionary to uppercase without iterating each key-valuepair?
Or how can i alter the qStrings["PARAM1"] so it ignores the case?
You can use StringComparer to find keys ignoring their case:
var qStrings = new Dictionary<string, string>(
HtmlPage.Document.QueryString,
StringComparer.OrdinalIgnoreCase)
Simplest Way
qStrings = qStrings .ToDictionary(k => k.Key.ToUpper(), k => k.Value.ToUpper());
Maybe you can do it like below:
Dictionary<string, string> qStrings = new Dictionary<string, string>();
foreach (var a in qStrings.Keys)
{
switch (a.ToUpper())
{
case "PARAM1":
break;
}
}
Without iterating is not possible. No matter what approach you use there is going to be some sort of iteration. The this is you need to limit the insertion of the data to a single unified casing rather than allowing users to input all sorts of casing.
Taking your example: "Param1", "param1", "pArAm1", a key will be created for each single one of these as they are treated as separate entities. The best way to handle that is to force the casing at the insertion rather than when querying for values.
For example:
void AddToDictionary(string key, string value)
{
qStrings[key.ToUpper()] = value;
}

Adding to a Dictionary within a dictionary

I am not a particularly confident programmer yet but am getting there.
My problem is that I have a
static Dictionary<string, Dictionary<string, List<string>>> testDictionary = ...
If the Dictionary doesn't contain the current key (string), I can easily add the key and another dictionary that has been populated, like so...
testDictionary.Add(userAgentResult, allowDisallowDictionary);
That works fine, my problem comes when I am trying to add the inner dictionary if the userAgentResult Key already exists.
I was hoping to do it this way...
testDictionary[userAgentResult].Add(allowDisallowDictionary);
but the .Add method wants two arguments, i.e. the string key and list value. So I went on to write this code...
//this list as the dictionary requires a list
List<string> testDictionaryList = new List<string>();
//this method returns a string
testDictionaryList.Add(regexForm(allowResult, url));
//this will add the key and value to the inner dictionary, the value, and then
//add this value at the userAgentKey
testDictionary[userAgentResult].Add(allowDisallowKey, testDictionaryList);
This also works, my problem is that this dictionary is added to numerous times, and when the inner dictionary already contains the key that is trying to be added, it obviously errors. So when
I would probably simplify this by having one dictionary and joining the keys thus "simulating" a grouping.
string key = userAgentResult + allowDisallowKey;
static Dictionary<string, List<string> testDictionary = ...
testDictionary[key] = list;
You simply need to manage one dictionary.
In this case what you need to do is not adding an entry to the inner dictionary. You need to add the value to the key-value pair of the outer dictionary. Only this time the value happens to be yet another dictionary :)
testDictionary[userAgentResult] = allowDisallowDictionary;
Maybe i don't get your problem. First make sure that dictionaries exist like so:
if (!testDictionary.ContainsKey(userAgentResult))
testDictionary[userAgentResult] = new Dictionary<string, List<string>>();
if (!testDictionary[userAgentResult].ContainsKey(allowDisallowKey))
testDictionary[userAgentResult][allowDisallowKey] = new List<string>();
Then you are free to add items like so:
testDictionary[userAgentResult][allowDisallowKey].Add("some value");
testDictionary[userAgentResult][allowDisallowKey].AddRange(someValueList);
When using nested dictionaries i normally use this approach:
private static Dictionary<string, Dictionary<string, List<string>>> _NestedDictionary = new Dictionary<string, Dictionary<string, List<string>>>();
private void DoSomething()
{
var outerKey = "My outer key";
var innerKey = "My inner key";
Dictionary<string, List<string>> innerDictionary = null;
List<string> listOfInnerDictionary = null;
// Check if we already have a dictionary for this key.
if (!_NestedDictionary.TryGetValue(outerKey, out innerDictionary))
{
// So we need to create one
innerDictionary = new Dictionary<string, List<string>>();
_NestedDictionary.Add(outerKey, innerDictionary);
}
// Check if the inner dict has the desired key
if (!innerDictionary.TryGetValue(innerKey, out listOfInnerDictionary))
{
// So we need to create it
listOfInnerDictionary = new List<string>();
innerDictionary.Add(innerKey, listOfInnerDictionary);
}
// Do whatever you like to do with the list
Console.WriteLine(innerKey + ":");
foreach (var item in listOfInnerDictionary)
{
Console.WriteLine(" " + item);
}
}
You need to do the same for the inner dictionary that you did for the outer one. First check if a list already exists for this key. If not create it. Then use the list that either existed or was created.

C# 4.0 - Multidimensional Associative Array (or way to mimic one?)

I'm an experienced PHP developer transitioning to C#. At present I am working on a Windows Forms application.
I found in my searches that C# doesn't support associative arrays in the same loose fashion PHP does. I have found info on Dictionary and something about "structs" which seem to be class objects.
The trouble I am having is getting my head around not only an Associative array, but a multi dimensional one that I want to use for keeping multiple counts in a series of loops.
The application is reading a text log file, searching for a predefined string, pulling out the date on that line when the string is found, and incrementing a count for that string match on that date.
In PHP, it would be as easy as this:
// Initialize
$count_array[$string_date][$string_keyword] = 0;
...
// if string is found
$count_array[$string_date][$string_keyword] += 1;
...
// To ouput contents of array
foreach($count_array as $date -> $keyword_count_array) {
echo $date; // output date
foreach($keyword_count_array as $keyword -> $count) {
echo $keyword . ": " . $count;
}
}
It seems to be a little more involved in C# (which isn't a bad thing). I have tried using an suggestion I found on another similar question but I don't really follow how to either increment or iterate/output the contents:
// Initialize
var count_array = new Dictionary<string, Dictionary<string, int>>();
count_array = null;
...
// if string is found - I think the second reference is supposed to be a Dictionary object??
count_array[string_date.ToShortDateString()][string_keyword]++;
...
// To ouput contents of "array"
foreach (KeyValuePair<string, Dictionary<string, int>> kvp in exportArray)
{
foreach(KeyValuePair<string, int> kvp2 in kvp.Value)
{
MessageBox.Show(kvp.Key + " - " + kvp2.Key + " = " + kvp2.Value);
}
}
Am I even on the right track? Or does someone have a better/cleaner method of mimicing the PHP code above?
UPDATE
With the above C# code, I actually get an error at the "// if string is found " line. The error is "Object reference is not set to an instance of an object". I am assuming that it is because I have a string in the secound reference, not a Dictionary object. So right now, I am unsure how to increment.
UPDATE 2
Thanks everyone for your time. Current code is now functional thanks to understanding how Dictionary's work. However all advice regarding the use of classes and objects for this situation is not lost either. I may refactor to suit.
The code itself looks sound, the only thing I see missing is there are no checks to see if the values exist before incrementing them.
Before you call
count_array[string_date.ToShortDateString()][string_keyword]++;
You'll need to do:
string shortDate = string_date.ToShortDateString();
if (!count_array.ContainsKey(shortDate))
{
count_array.Add(shortDate, new Dictionary<string, int>());
}
if (!count_array[shortDate].ContainsKey(string_keyword))
{
count_array[shortDate].Add(string_keyword, 0);
}
Before you try incrementing anything.
You need to initialize your dictionary entries by calling .Add or ["key"] = value. Calling ++ on an uninitialized dictionary entry won't work. Depending on what exactly it is you're trying to accomplish though it might be a good idea to use a class.
You can use a tuple to create a multi-dimensional key for use in a Dictionary.
Dictionary<Tuple<TKey1,TKey2>,TValue>
Or a Dictionary of Dictionary:
Dictionary<TKey1,Dictionart<TKey2,Tvalue>>
The second one is more annoying to work with, but has the upside that you can index into it with just the first key and then get all key-value pairs associated with that key.
But perhaps you can use some linq, but your code is a bit incomplete for that.
What about creating a class for this?
public class LogEntry
{
private List<int> _lines = new List<int>();
public string LogContent { get;set; }
public DateTime Time { get;set; }
public List<int> Lines { get { return _lines; } }
}
You'd still have a dictionary of probably DateTime, LogEntry? Not entirely sure what exactly you need / what the key is.
Anyways, creating a class seems to be the "correct" way as you can express your intend more clearly.
Your approach can work, however, you need to understand Dictionary is a reference type, which means it has to be created prior to use. You create the “top-level” Dictionary, but the “second-level” dictionaries need to be created as well. But in
count_array[string_date.ToShortDateString()][string_keyword]++;
you count on count_array[string_date.ToShortDateString()] being already created (so that it can be queried). And another problem is that Dictionary<Key, Value> behavior is that an attempt to access an item which does not exist results in an exception (KeyNotFoundException). There is a more lenient TryGetValue method for you to use. Combined, you need to do something along the lines of:
// Initialize
var count_array = new Dictionary<string, Dictionary<string, int>>();
// if string is found - I think the second reference is supposed to be a Dictionary object??
Dictionary<string, int> perDateDict;
var dateKey = string_date.ToShortDateString();
if (!count_array.TryGetValue(dateKey, out perDateDict)
{
perDateDict = new Dictionary<string, int>();
count_array.Add(adteKey, perDateDict);
}
int prevValue;
// note that when not found, prevValue will be zero, which is what we need
perDateDict.TryGetValue(string_keyword, out prevValue);
perDateDict[string_keyword] = prevValue+1;
// To ouput contents of "array"
foreach (KeyValuePair<string, Dictionary<string, int>> kvp in exportArray)
{
foreach(KeyValuePair<string, int> kvp2 in kvp.Value)
{
MessageBox.Show(kvp.Key + " - " + kvp2.Key + " = " + kvp2.Value);
}
}
One thing you must be make sure Dictionary is not a ValueType and is not auto initialized.
Hence when you say count_array = null it means you are resetting the reference to null location. Just remove the line.
Your code should look like :
var count_array = new Dictionary<string, Dictionary<string, int>>();
// if string is found - I think the second reference is supposed to be a Dictionary object??
string dt = DateTime.Now.ToShortDateString();
count_array[dt] = new Dictionary<string, int>(); //It is important as you should always give appropriate refernece before doing a fetch.
count_array[dt]["key"] = 0; //Value types are defaults to 0 so it is not explicitely required.
//Now you can do
count_array[dt]["key"]++;
// To ouput contents of "array"
foreach (KeyValuePair<string, Dictionary<string, int>> kvp in count_array)
{
foreach (KeyValuePair<string, int> kvp2 in kvp.Value)
{
Console.WriteLine(kvp.Key + " - " + kvp2.Key + " = " + kvp2.Value);
}
}
You can also use ?? operator to ensure that when Dictionary is null, you assign a new reference.
count_array[dt] = count_array[dt] ?? new Dictionary();
I hope this will help you even you should recode this properly.
You need to start thinking in OO terms. In production code I would give the classes some destination to print to, instead of going directly to Console, and maybe use strategy or similar to format the text, but essentially this is the OO way of thinking about the problem.
class Log {
Dictionary<DateTime, List<LogEntry>} Entries { get; private set; }
public void PrintLogs()
{
foreach (var date in Entries.Keys)
{
Console.WriteLine(date);
foreach (var entry in Entries[date])
{
entry.PrintEntry();
}
}
}
}
class LogEntry {
public List<string> EntryLines { get; set; }
public DateTime Date { get; set; }
public void PrintEntry()
{
foreach (var line in EntryLines)
Console.WriteLine(line);
}
}

Categories