Print list-objects within sortedDictionary - c#

So I'm trying to print out the members of my list. I'm using the following dictionary-structure: SortedDictionary<string,List<int>> where i'm using a string as the key.
In my function ShowContents I'm trying to print out what entry i'm looking at, and the amount of elements, as well as what the elements are. This is where i'm struggling. I'm just getting System.Collections.Generic.List1[System.Int32]instead of the objects.
Here's my current code:
SortedDictionary<string,List<int>> jumpStats = new SortedDictionary<string,List<int>>(); // jumpstats[0] == (volt, 10m)
public string ShowContents()
{
var sb = new StringBuilder();
foreach (KeyValuePair<string, List<int>> item in jumpStats)
{
sb.Append(string.Format("{0}: has {1} entries with values {2}", item.Key, item.Value.Count(), item.Value));
}
return sb.ToString();
}
public SortedDictionary<string,List<int>> addjumpStats() //Adding information about the jump to the dictionary
{
try
{
jumpStats.Add("Volt", new List<int>());
jumpStats["Volt"].Add(12);
jumpStats["Volt"].Add(13);
jumpStats["Volt"].Add(15);
}
catch (ArgumentException)
{
Console.WriteLine("An Element already exists with the same key");
}
return jumpStats;
}
Example output right now: Volt: 3 System.Collections.Generic.List1[System.Int32]

In your append function you're outputting item.Value which is a List<int> hence why you are seeing the class name - the ToString function of a List does not know to concatenate all the values in the list together - it merely returns the class name. You need to tell it what to do. An easy way to do this is to use string.join:
string.Join(",", item.Value)
And in context:
var sb = new StringBuilder();
foreach (KeyValuePair<string, List<int>> item in jumpStats)
{
sb.Append(string.Format("{0}: has {1} entries with values {2}", item.Key, item.Value.Count(), string.Join(",", item.Value));
}
return sb.ToString();

Related

Extract key value pair from dictionary

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]);

How to update a c# dictionary where key is set, value is empty in nested foreach loop

just learning c# so I want to know why my code isn't working as well as any helpful input on how to make this easier. This is just part of a little tool I'm trying to write that will take two files and put them together to build a .json file so I thought to start with a dictionary object. Thank you!
I have 2 text files, one has the list of dictionary keys, the other dictionary values. I want to combine those two text files into one dictionary object but for some reason it's populating the key correctly but the value's are all the same, the last one in the list. So it gets to the bottom of the list of keys and then since it's on the last key value it just repeats the last value for all keys. For example:
txt file 1:
one
two
three
txt file 2:
peach
lime
mango
output:
one, mango
two, mango
three, mango
I want:
one, peach
two, lime
three, mango
This is my code:
try
{
string path1 = #"C:\temp\langVars.txt";
string path2 = #"C:\temp\langValues.txt";
string[] readVars = File.ReadAllLines(path1);
string[] readVals = File.ReadAllLines(path2);
Dictionary<string, string> dictionaryVars = new Dictionary<string, string>();
foreach (string s1 in readVars)
{
dictionaryVars.Add(s1, "");
foreach (string s2 in readVals)
dictionaryVars[s1] = (s2);
}
foreach (KeyValuePair<string, string> kvp in dictionaryVars)
{
Console.WriteLine("{0}, {1}", kvp.Key, kvp.Value);
}
You should not use a nested foreach loop here:
foreach (string s1 in readVars)
{
dictionaryVars.Add(s1, "");
foreach (string s2 in readVals)
dictionaryVars[s1] = (s2);
}
A nested foreach loop means that you are doing dictionaryVars[s1] = (s2); for each s2 there is, for the same s1. That is:
dictionaryVars["one"] = "peach";
dictionaryVars["one"] = "lime";
dictionaryVars["one"] = "mango";
dictionaryVars["two"] = "peach";
dictionaryVars["two"] = "lime";
dictionaryVars["two"] = "mango";
dictionaryVars["three"] = "peach";
dictionaryVars["three"] = "lime";
dictionaryVars["three"] = "mango";
So you would end up with all three keys having the value mango.
You are also printing the key value pairs from another dictionary called dictionary, rather than dictionaryVars.
You should use a single for loop that iterates both arrays at the same time:
for (int i = 0 ; i < readVars.Length ; i++) {
dictionaryVars.Add(readVars[i], readVals[i]);
}
And print the contents of dictionaryVars instead:
foreach (KeyValuePair<string, string> kvp in dictionaryVars) // <--- here!
{
Console.WriteLine("{0}, {1}", kvp.Key, kvp.Value);
}

Output inner dictionary KeyValuePair to Console

Struggling with this code, very new to c# and I've tried multiple answers on stackoverflow before writing this question so please hear me out...
var onlinePlayers = new Dictionary<int, Dictionary<string,string>>();
var count = 0;
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
onlinePlayers.Add(
count,
new Dictionary<string, string> {
{ "SteamID", player.userID.ToString() },
{ "PlayerName", player.displayName.ToString() },
{ "IPAddress", Regex.Replace(player.net.connection.ipaddress, #":{1}[0-9]{1}\d*", "").ToString }
}
);
count += 1;
}
foreach (var k in onlinePlayers.Keys)
{
foreach (KeyValuePair<string, string> pair in onlinePlayers[k])
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
}
I'm expecting to see
SteamID: 1231231221321
PlayerName: HelloWorld
IPAddress: 127.0.0.1
for each item in the collection.
Compiler error:
Error while compiling StatLogger.cs(38,111): error CS1503: Argument #2 cannot
convert method group expression to type string
You're missing the parentheses () at the end of your .ToString().
{ "IPAddress", Regex.Replace(player.net.connection.ipaddress,
#":{1}[0-9]{1}\d*", "").ToString }
Update :
Also player.net.connection.ipaddress.ToString()
The above will turn the IP into a string and that should prevent the error.
You're trying to enumerate the Dictionary's key, rather than the Dictionary itself.
Try this:
foreach (player in onlinePlayers) {
foreach (playerInfo in player.Value) {
Console.WriteLine("{0}: {1}", playerInfo.Key, playerInfo.Value);
}
}
See if that helps.

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.

Dictionary<string, List <KeyValuePair<string,string>>>

I have created:
Dictionary<string, List <KeyValuePair<string,string>>> diction = new Dictionary<string, List<KeyValuePair<string,string>>>();
Later I've added to that list:
diction.Add(firststring, new List<KeyValuePair<string,string>>());
diction[firststring].Add(new KeyValuePair<string, string>(1ststringlist, 2ndstringlist));
So now, If I want to read and show on screen this dictionary, how would I do it with foreach loop ? It's like 3 dimmension syntax, don't now how to create it and access it.
Also can anyone explain how to read this part?
diction[firststring].Add
What this marks [] excatly mean? I read whole dictionary there?
thank You for answer and Your time.
Dictionaries store key / value pairs. In your case, your key type is string and value type is List <KeyValuePair<string,string>>.So when you do:
diction[firststring]
firststring is your Key and you are trying to access a List <KeyValuePair<string,string>>.Your best option is nested loops I think.if you want to display all values. For example:
foreach(var key in dict.Keys)
{
// dict[key] returns List <KeyValuePair<string,string>>
foreach(var value in dict[key])
{
// here type of value is KeyValuePair<string,string>
var currentValue = value.Value;
var currentKey = value.Key;
}
}
For printing the datastructure, try this:
// string.Join(separator, enumerable) concatenates the enumerable together with
// the separator string
var result = string.Join(
Environment.NewLine,
// on each line, we'll render key: {list}, using string.Join again to create a nice
// string for the list value
diction.Select(kvp => kvp.Key + ": " + string.Join(", ", kvp.Value)
);
Console.WriteLine(result);
In general, to loop over the values of a dictionary, you can use foreach or LINQ just like with any IEnumerable data structure. IDictionary is an IEnumerable>, so the foreach variable will be of type KeyValuePair.
The syntax diction[key] allows you to get or set the value of the dictionary stored at the index key. It's similar to how array[i] lets you get or set the array value at index i. For example:
var dict = new Dictionary<string, int>();
dict["a"] = 2;
Console.WriteLine(dict["a"]); // prints 2
If all you need to do is store rows of 3 string values each, then the data structure you are using is far too complicated.
Here's a much simpler example, based on the Tuple class:
public class Triplet : Tuple<string, string, string>
{
public Triplet(string item1, string item2, string item3) : base(item1, item2, item3)
{
}
}
So you just define a class Triplet that holds 3 strings, like above. Then you simply create a List of Triplets in your code:
// Your code here
var data = new List<Triplet>();
// Add rows
data.Add(new Triplet("John", "Paul", "George"));
data.Add(new Triplet("Gene", "Paul", "Ace"));
// Display
foreach(Triplet row in data)
{
Console.WriteLine("{0}, {1}, {2}", row.Item1, row.Item2, row.Item3);
}
and this is far simpler to read, understand, and maintain.

Categories