Extract key value pair from dictionary - c#

I'm at the first step in programming and i'm stuck with a problem with Dictionary(key value) pair.
The statement of the problem is:
Write a console application that extracts and prints the key and value on a line.
Example:
For input data:
year:2018
The console will display:
year
2018
here is my code:
string inputData = Console.ReadLine();
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add(inputData, 2018 );
foreach (KeyValuePair<string, int> kvp in dictionary)
{
Console.WriteLine("{0}\n{1}", kvp.Key, kvp.Value);
}

// expects year:2018
var inputData = Console.ReadLine();
// split by ':' to get 'year' and '2018' values
var values = inputData.Split(':');
// creates a dictionary
var dictionary = new Dictionary<string, int>();
// add the 'year' string as key and '2018' as value
dictionary.Add(values[0], Convert.ToInt32(values[1]));
// print all the dictionary
foreach (var kvp in dictionary)
{
Console.WriteLine("{0}\n{1}", kvp.Key, kvp.Value);
}
However, the problem description is not asking you to use a dictionary.
So, instead of creating a dictionary, you can simply print the values.
var inputData = Console.ReadLine();
var values = inputData.Split(':');
Console.WriteLine(values[0]);
Console.WriteLine(values[1]);

Related

C# How can I print all elements from List<Dictionary<string,string>> on the console?

I’m a rookie in programming and I have a problem understanding how to print elements from a List.
In the task I’ve been given, I receive:
List<Dictionary<string,string>>() list = new
List<Dictionary<string,string>>();
list.Add(processString(string, string));
list.Add(processString(string, string));
The processStrig is a Dictionary<string,string> and the keys are the same for both records.
I tried to create a new Dictionary and then populate it with foreach:
Dictionary<string,string>() dict = new Dictionary<string, string>();
foreach (Dictionary<string,string>r in list)
{
foreach (string inner in r.Keys)
{
if (!dict.ContainsKey(inner))
{
dict.Add(inner, r[inner]);
}
}
}
and then print the new dict with another foreach, but it shows me only the first input because the keys are the same. So basically my question is how to print the both inputs? The output should look like this:
The output should look like this:
[0]
"count":"some string"
"order":"some string"
[1]
"count":"some other string"
"order":"some other string"
If you are looking for a loop solution, you can try something like this:
List<Dictionary<string, string>> list = ...
for (int i = 0; i < list.Count; ++i) {
Console.WriteLine($"[{i}]");
if (list[i] == null)
Console.WriteLine("[null]");
else
foreach (var pair in list[i])
Console.WriteLine($"\"{pair.Key}\" : \"{pair.Value}\"");
}
Let's have a method that makes you a dictionary:
public static Dictionary<string, string> MakeMeADictionary(string value1, string value2){
var d = new Dictionary<string, string>();
d["key1"] = value1;
d["key2"] = value2;
return d;
}
Let's call it twice, adding the results to a List:
var listOfDicts = new List<Dictionary<string, string>>();
listOfDicts.Add(MakeMeADictionary("first val", "second val"));
listOfDicts.Add(MakeMeADictionary("third val", "fourth val"));
Let's enumerate the list, and then each dictionary inside it:
foreach(var dict in listOfDicts){
Console.WriteLine("Enumerating a dictionary");
foreach(var keyValuePair in dict)
Console.WriteLine($"Key is: {keyValuePair.Key}, Value is: {keyValuePair.Value}");
}
Result:
Enumerating a dictionary
Key is: key1, Value is: first val
Key is: key2, Value is: second val
Enumerating a dictionary
Key is: key1, Value is: third val
Key is: key2, Value is: fourth val
Strive for variable names that make your code make sense; plurals or names of colelction types for collections, foreach vars that singularly make sense for the plural being enumerated etc.. If this were a less contrived example, and e.g. it were a List<Person> I'd call it people, perhaps, and have foreach(var person in people).. I couldn't understand your choice of r in foreach(var r in list)

Argument Exception "Item with Same Key has already been added"

I keep getting an error with the following code:
Dictionary<string, string> rct3Features = new Dictionary<string, string>();
Dictionary<string, string> rct4Features = new Dictionary<string, string>();
foreach (string line in rct3Lines)
{
string[] items = line.Split(new String[] { " " }, 2, StringSplitOptions.None);
rct3Features.Add(items[0], items[1]);
////To print out the dictionary (to see if it works)
//foreach (KeyValuePair<string, string> item in rct3Features)
//{
// Console.WriteLine(item.Key + " " + item.Value);
//}
}
The error throws an ArgumentException saying,
"An item with the same key has already been added."
I am unsure after several Google searches how to fix this.
Later in the code I need to access the dictionary for a compare function:
Compare4To3(rct4Features, rct3Features);
public static void Compare4To3(Dictionary<string, string> dictionaryOne, Dictionary<string, string> dictionaryTwo)
{
//foreach (string item in dictionaryOne)
//{
//To print out the dictionary (to see if it works)
foreach (KeyValuePair<string, string> item in dictionaryOne)
{
Console.WriteLine(item.Key + " " + item.Value);
}
//if (dictionaryTwo.ContainsKey(dictionaryOne.Keys)
//{
// Console.Write("True");
//}
//else
//{
// Console.Write("False");
//}
//}
}
This function isn't completed, but I am trying to resolve this exception. What are the ways I can fix this exception error, and keep access to the dictionary for use with this function? Thank you
This error is fairly self-explanatory. Dictionary keys are unique and you cannot have more than one of the same key. To fix this, you should modify your code like so:
Dictionary<string, string> rct3Features = new Dictionary<string, string>();
Dictionary<string, string> rct4Features = new Dictionary<string, string>();
foreach (string line in rct3Lines)
{
string[] items = line.Split(new String[] { " " }, 2, StringSplitOptions.None);
if (!rct3Features.ContainsKey(items[0]))
{
rct3Features.Add(items[0], items[1]);
}
////To print out the dictionary (to see if it works)
//foreach (KeyValuePair<string, string> item in rct3Features)
//{
// Console.WriteLine(item.Key + " " + item.Value);
//}
}
This simple if statement ensures that you are only attempting to add a new entry to the Dictionary when the Key (items[0]) is not already present.
If you want "insert or replace" semantics, use this syntax:
A[key] = value; // <-- insert or replace semantics
It's more efficient and readable than calls involving "ContainsKey()" or "Remove()" prior to "Add()".
So in your case:
rct3Features[items[0]] = items[1];
As others have said, you are adding the same key more than once. If this is a NOT a valid scenario, then check Jdinklage Morgoone's answer (which only saves the first value found for a key), or, consider this workaround (which only saves the last value found for a key):
// This will always overwrite the existing value if one is already stored for this key
rct3Features[items[0]] = items[1];
Otherwise, if it is valid to have multiple values for a single key, then you should consider storing your values in a List<string> for each string key.
For example:
var rct3Features = new Dictionary<string, List<string>>();
var rct4Features = new Dictionary<string, List<string>>();
foreach (string line in rct3Lines)
{
string[] items = line.Split(new String[] { " " }, 2, StringSplitOptions.None);
if (!rct3Features.ContainsKey(items[0]))
{
// No items for this key have been added, so create a new list
// for the value with item[1] as the only item in the list
rct3Features.Add(items[0], new List<string> { items[1] });
}
else
{
// This key already exists, so add item[1] to the existing list value
rct3Features[items[0]].Add(items[1]);
}
}
// To display your keys and values (testing)
foreach (KeyValuePair<string, List<string>> item in rct3Features)
{
Console.WriteLine("The Key: {0} has values:", item.Key);
foreach (string value in item.Value)
{
Console.WriteLine(" - {0}", value);
}
}
To illustrate the problem you are having, let's look at some code...
Dictionary<string, string> test = new Dictionary<string, string>();
test.Add("Key1", "Value1"); // Works fine
test.Add("Key2", "Value2"); // Works fine
test.Add("Key1", "Value3"); // Fails because of duplicate key
The reason that a dictionary has a key/value pair is a feature so you can do this...
var myString = test["Key2"]; // myString is now Value2.
If Dictionary had 2 Key2's, it wouldn't know which one to return, so it limits you to a unique key.
That Exception is thrown if there is already a key in the dictionary when you try to add the new one.
There must be more than one line in rct3Lines with the same first word. You can't have 2 entries in the same dictionary with the same key.
You need to decide what you want to happen if the key already exists - if you want to just update the value where the key exists you can simply
rct3Features[items[0]]=items[1]
but, if not you may want to test if the key already exists with:
if(rect3Features.ContainsKey(items[0]))
{
//Do something
}
else
{
//Do something else
}
I suggest .NET's TryAdd:
https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.tryadd?view=net-7.0
I suggest a extension method for environments where .NET's TryAdd is not available:
public static class DictionaryUtils
{
/// <summary>
/// Prevents exception "Item with Same Key has already been added".
/// </summary>
public static void TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, value);
}
}
}
Clear the dictionary before adding any items to it. I don't know how a dictionary of one object affects another's during assignment but I got the error after creating another object with the same key,value pairs.
NB:
If you are going to add items in a loop just make sure you clear the dictionary before entering the loop.

Logging Hashtable Properties

I have a Hashtable that I am trying to log the values for. the name of the Hashtable is "props".
My code is as follows:
Dictionary<string, string> keyPairs = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> items in props)
{
keyPairs.Add(items.Key, items.Value);
}
Logging.Instance.WriteInformation(string.Format("Key: {0} \t Value: {1}", keyPairs.Keys, keyPairs.Values));
However this results in a InvalidCastException at runtime.
Is there an easier/more sensible way to log key/value pairs?
Ideally the output would look something like so:
key1 value1
key2 value2
key3 value3
etc.
As an addition thought, in debugging, the exception seems to occur right at the start of the foreach loop. I have also tried setting it up as KeyValuePair<string, object> but I get the same InvalidCastException.
Would this possibly have something to do with KeyValuePair being inside System.Collections.Generic and Hashtable being inside System.Collections?
You can either use a loop or, if you want an one-liner:
var allPairs = string.Join(Environment.NewLine,
keyPairs.Select(kvp => string.Format("Key: {0} \t Value: {1}", kvp.Key, kvp.Value)));
Logging.Instance.WriteInformation(allPairs);
Sure, just loop:
for (var entry : keyPairs)
{
Logging.Instance.WriteInformation(string.Format("Key: {0} \t Value: {1}",
entry.Key, entry.Value);
}
It's only a few lines - you could easily put it in a method if you need it in more than one place.
Log while you are looping.
Dictionary<string, string> keyPairs = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> items in props)
{
keyPairs.Add(items.Key, items.Value);
Logging.Instance.WriteInformation(string.Format("Key: {0} \t Value: {1}", items.Key, items.Value));
}

Making a List<string> from Dictionary<string, string>

I was wondering if it were possible to make a list from the dictionary values where the key is a specified value?
The dictionary would like this:
Sidcup - DPC1
Sidcup - DPC2
Blackheath - DPC3
Blackheath - DPC4
Bexleyheath - DPC5
In fact, I'm not entirely implementing a Dictionary as above is a good idea. Here is its implementation:
DataSet ds = EngineBllUtility.GetDPCsForImportFile(connectionString, fileID);
if (ds.Tables.Count > 0)
{
DataTable dtDPCs = EngineBllUtility.GetDPCsForImportFile(connectionString, fileID).Tables[0];
Dictionary<string, string> preliminaryList = new Dictionary<string, string>();
if (dtDPCs.Columns.Contains("DPCNumber") && dtDPCs.Columns.Contains("BranchName"))
foreach (DataRow dataRow in dtDPCs.Rows)
{
preliminaryList.Add(dataRow["BranchName"].ToString(), dataRow["DPCNumber"].ToString());
}
I have the following code: (Excuse the last line, its just so you have an idea of what I'm trying to do).
foreach (string branch in branchNames)
{
string subfolder = System.IO.Path.Combine(saveLocation, branch);
System.IO.Directory.CreateDirectory(subfolder);
List<string> certificateList = new List<string>();
certificateList.Add(DPCNumber in preliminaryList where Key = branch);
}
In the above the branch is the key from the Dictionary. I need to iterate through because it needs to create a new folder and then do something with the certificateList I am creating.
Sure:
private static void TestZip()
{
Dictionary<string, string> stringstringdic = new Dictionary<string, string>();
stringstringdic.Add("1", "One");
stringstringdic.Add("2", "Two");
stringstringdic.Add("3", "Three");
stringstringdic.Add("4", "Four");
stringstringdic = stringstringdic.Where(pair => pair.Key != "1")
.ToDictionary(pair => pair.Key, pair => pair.Value);
List<string> stringlist = stringstringdic.Keys.Concat(stringstringdic.Values).ToList();
foreach (string str in stringlist)
{
Console.WriteLine(str);
}
}
//Output:
//2
//3
//4
//Two
//Three
//Four
Of course, you'll have to change the Where clause to reflect your real need.
If I understood you right, it's like .Where(pair => pair.Key == branch)
If I understand you correctly you want to add the value based on a key to a separate List?
certificateList.Add(preliminaryList[branch])
This is simplified as I really need to see the declaration of preliminaryList to know how DPCNumber fits into all of it. Could it be...
certificateList.Add(preliminaryList[branch].ToString())
To simply create a list of keys you can do the following.
var dictionary = new Dictionary<string, string>();
dictionary.Add("key1", "value1");
dictionary.Add("key2", "value2");
dictionary.Add("key3", "value3");
dictionary.Add("key4", "value4");
dictionary.Add("key5", "value5");
var list = dictionary.Keys.ToList();
This should give you a list with values "key1", "key2", "key3", "key4", "key5".
You can put a where clause in to filter out certain keys. The following gives all keys which contain a "2" (random example), resulting in just "key2".
var filteredList = dictionary.Keys.Where(key => key.Contains("2")).ToList();
Edit:
To get a value given a specific key.
string value = dictionary["key1"];
Note, the key is a dictionary must be unique, so for a given key you will only ever get a single value back and not a list of values.

How to loop through this dictionary

I have declared a dictionary like this:
Dictionary<string, KeyValuePair<string, string>> dc = new Dictionary<string, KeyValuePair<string, string>>();
now how can I loop through it? I wanted something like the following so I created that dictionary:
name1
oldValue1
newValue1
name2
oldValue2
newValue2
...
You can loop through it like so
foreach (var pair in dc)
{
string name = pair.Key;
string oldValue = pair.Value.Key;
string newValue = pair.Value.Value;
// use the values
}
But I have a feeling you're using the wrong tool for the job. It sounds to me like you really need to go ahead and define a proper class to hold the names and values, and then just work with a List<T> of that class.
foreach( KeyValuePair<string, string> kvp in dc )
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
When you loop a dictionary you use KeyValuePair that is generic. Since your dictionary contain the key as string and the value as string, this one will take also a string for both.
You can access the key with kvp.Key and the value with kvp.Value.
For your example, you are using a Dictionary of string that contain a value of KeyValuePair.
So, you can have the exact print you want with :
foreach( KeyValuePair<string, KeyValuePair<string,string>> kvp in dc )
{
Console.WriteLine(kvp.Key + " " + kvp.Value.Key + " "+ kvp.Value.Value);
}

Categories