How to join values from dictionary? - c#

I have dictionary code as follows:
int entry=0;
string[] numbers ={"123","123","123","456","123"};
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
foreach (string number in numbers)
{
if (dictionary.ContainsKey("ABC"))
{
}
else if (!dictionary.ContainsKey("ABC") && entry==0)
{
dictionary.Add("ABC", new List<string>());
dictionary["ABC"].Add(number);
entry = 1;
}
else if (!dictionary.ContainsKey("ABC") && entry == 1)
{
dictionary["ABC"].Add(number);
}
}
foreach(KeyValuePair<string,string> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,kvp.Value);
}
Console.ReadKey();
I want output like as follows Key="ABC",Value="123,456" i.e. I need to print all the dictionary values only once without repeat. In above string array 123 came 4 times.But I want to print that only one time and need 456 also and also joint that values with comma(",").So I need output like Key="ABC",Value="123,456". Please share your ideas. Thanks in advance.

I need to print all the dictionary values only once without repeat.
Use Distinct method.
joint that values with comma(",")
Use String.Join method.
foreach(var kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}",
kvp.Key,
String.Join(", " kvp.Value.Distinct())
);
}

You can try like this:
foreach(var value in dictionary.Values.Distinct())
{
names = String.Join(", ", value);
}

The following for loop variable is incorrect, I think:
foreach(KeyValuePair<string,string> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,kvp.Value);
}
It should read: then note the difference in the writeline
foreach(KeyValuePair<string,List<string>> kvp in dictionary)
{
Console.WriteLine("Key={0},Value = {1}", kvp.Key,string.Join(",", kvp.Value.ToArray()));
}

You can use this simple linq to flatten and join all your dictionary contents:
var result = string.Join(" - ", dic.Select(kvp => string.Format("Key={0}, Values={1}", kvp.Key, string.Join(", ",kvp.Value.Distinct()))));

Instead of using this array :
string[] numbers = {"123","123","123","456","123"};
Add another array as :
string[] uniqueNumbers = numbers.Distinct().ToArray();
and now use this array with unique values to add to the dictionary.

Related

c#: How to iterate through a List<>, that is a value in a dictionary?

Right now I have a dictionary being populated with an account as key, and a List as value. I believe my code is working to populate it. But my next step is to iterate through that List associated with a particularly key and do stuff with the list (get sums for each field). I am not that familiar with dictionaries so I am not sure how to access the values and perform an action. I would like to do this summation and print it out in my for each loop, when I exit the while loop.
1) If I could figure out how to access each field in DataRecords (inside the foreach loop), I could likely figure out how to do the summation.
2) Also looking for a way to print the values so I can see if it is even populated correctly.
static void Main(string[] args)
{
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
while (!r.EndOfStream)
{
if (control == "1")
{
// Need to add List<Datarecords> into dictionary...
if (vSummaryResults.ContainsKey(records.account))
{
vSummaryResults[records.account].Add(records);
}
else
{
vSummaryResults.Add(records.account, new List<DataRecord>());
vSummaryResults[records.account].Add(records);
}
}
}
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
vWriteFile.Close();
Console.ReadLine();
}
Here is my DataRecord class that I am using as the object in the List.
public class DataRecord
{
fields.....
}
For iterations over a dictionary, we use KeyValuePair:
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key;
List<DataRecord> list = kvp.Value;
Console.WriteLine("Key = {0}, contains {1} values:", key, list.Count);
foreach (DataRecord rec in list)
{
Console.WriteLine(" - Value = {0}", rec.ToString()); // or whatever you do to put list value on the output
}
}
You need another loop inside the first to get values in your list.
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
If you know the key:
foreach (List<DataRecord> rec in vSummaryResults[key])
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
I made an example with a simple situation. Its a list of strings, but you can do the object.ToString() to get some tekst;
To loop over the list contained by the key you need to iterate over that list again that is what the 2nd foreach does.
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
List<String> ls = new List<string>();
ls.Add("item1");
ls.Add("item2");
dictionary.Add("it1", ls);
dictionary.Add("it2", ls);
foreach (var item in dictionary)
{
foreach(var it in item.Value)
{
Console.WriteLine(it);
}
}
You have a dictionary
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
You could do a
foreach (List<DataRecord> recs in vSummaryResults.Values)
{
foreach (DataRecord rec in recs)
Console.WriteLine(rec.Something);
}
You haven't specified what DataRecord looks like, but you would get a list of list. There's probably a lovely Linq expression that could do the same.
I understand it from reading your code, you have a dictionary where each key has a list of type DataRecord.
With your current loop
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
You looped through each List of type DataRecord. To access the data stored in each object in each list you will need to include another foreach loop to loop through the objects in the list.
foreach (var rec in vSummaryResults.Values)
{
// At this point we have access to each individual List<DataRecord>
foreach(var SingleDataRecordObj in rec)
Console.WriteLine(ingleDataRecordObj.membervariablename)
//From here we are able to list the individual variable member names of values that are in the DataRecord data type, showing all of the information in each list that is stored in the values of the dictionary
}
You can't modify the data in the foreach loop, but you could add them a more simple data structure to perform whatever commutation you wanted etc.
Here is the code for exactly what I needed to do. Working the way I need it to now, thanks for everyone's help.
int iSumOpen = 0;
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key; //assigns key
List<DataRecord> list = kvp.Value; //assigns value
Console.WriteLine("Key = {0}", key);
iSumOpen = 0;
foreach (DataRecord rec in list)
{
if (vSummaryResults.ContainsKey(key))
{
iSumOpen += rec.open;
}
else
{
vSummaryResults.Add(key, list);
}
}
Console.WriteLine(iSumOpen);
}

How to display all mistaken words

I have some text in richTextBox1.
I have to sort the words by their frequency and display them in richTextBox2. It seems to work.
Have to find all mistaken words and display them in richTextBox4. I'm using Hunspell.
Apparently I'm missing something. Almost all words are displayed in richTextBox4 not only the wrong ones.
Code:
foreach (Match match in wordPattern.Matches(str))
{
if (!words.ContainsKey(match.Value))
words.Add(match.Value, 1);
else
words[match.Value]++;
}
string[] words2 = new string[words.Keys.Count];
words.Keys.CopyTo(words2, 0);
int[] freqs = new int[words.Values.Count];
words.Values.CopyTo(freqs, 0);
Array.Sort(freqs, words2);
Array.Reverse(freqs);
Array.Reverse(words2);
Dictionary<string, int> dictByFreq = new Dictionary<string, int>();
for (int i = 0; i < freqs.Length; i++)
{
dictByFreq.Add(words2[i], freqs[i]);
}
Hunspell hunspell = new Hunspell("en_US.aff", "en_US.dic");
StringBuilder resultSb = new StringBuilder(dictByFreq.Count);
foreach (KeyValuePair<string, int> entry in dictByFreq)
{
resultSb.AppendLine(string.Format("{0} [{1}]", entry.Key, entry.Value));
richTextBox2.Text = resultSb.ToString();
bool correct = hunspell.Spell(entry.Key);
if (correct == false)
{
richTextBox4.Text = resultSb.ToString();
}
}
In addition to the above answer (which should work if your Hunspell.Spell method works correctly), I have a few suggestions to shorten your code. You are adding Matches to your dictionary, and counting the number of occurrences of each match. Then you appear to be sorting them in descending value of the frequency (so the highest occurrence match will have index 0 in the result). Here are a few code snippets which should make your function a lot shorter:
IOrderedEnumerable<KeyValuePair<string, int>> dictByFreq = words.OrderBy<KeyValuePair<string, int>, int>((KeyValuePair<string, int> kvp) => -kvp.Value);
This uses the .NET framework to do all your work for you. words.OrderBy takes a Func argument which provides the value to sort on. The problem with using the default values for this function is it wants to sort on the keys and you want to sort on the values. This function call will do exactly that. It will also sort them in descending order based on the values, which is the frequency that a particular match occurred. It returns an IOrderedEnumerable object, which has to be stored. And since that is enumerable, you don't even have to put it back into a dictionary! If you really need to do other operations on it later, you can call the dictByFreq.ToList() function, which returns an object of type: List>.
So your whole function then becomes this:
foreach (Match match in wordPattern.Matches(str))
{
if (!words.ContainsKey(match.Value))
words.Add(match.Value, 1);
else
words[match.Value]++;
}
IOrderedEnumerable<KeyValuePair<string, int>> dictByFreq = words.OrderBy<KeyValuePair<string, int>, int>((KeyValuePair<string, int> kvp) => -kvp.Value);
Hunspell hunspell = new Hunspell("en_US.aff", "en_US.dic");
StringBuilder resultSb = new StringBuilder(dictByFreq.Count);
foreach (KeyValuePair<string, int> entry in dictByFreq)
{
resultSb.AppendLine(string.Format("{0} [{1}]", entry.Key, entry.Value));
richTextBox2.Text = resultSb.ToString();
bool correct = hunspell.Spell(entry.Key);
if (correct == false)
{
richTextBox4.Text = entry.Key;
}
}
Your are displaying on richtextbox4 the same as in richtextbox2 :)
I think this should work:
foreach (KeyValuePair<string, int> entry in dictByFreq)
{
resultSb.AppendLine(string.Format("{0} [{1}]", entry.Key, entry.Value));
richTextBox2.Text = resultSb.ToString();
bool correct = hunspell.Spell(entry.Key);
if (correct == false)
{
richTextBox4.Text += entry.Key;
}
}

Error using a dictionary in c#

I am trying to search through a dictionary to see if it has a certain value and if so then to change it.
Here is my code:
foreach (var d in dictionary)
{
if (d.Value == "red")
{
d.Value = "blue";
}
}
In visual studio when i step through the code debugging it i can see it change the value then when it hits the foreach loop to reiterate again it throws an exception
"Collection was modified; enumeration operation may not execute"
How do i fix this?
You can't change it in the middle of the foreach - you'll need to come up with some other mechanism, such as:
// Get the KeyValuePair items to change in a separate collection (list)
var pairsToChange = dictionary.Where(d => d.Value == "red").ToList();
foreach(var kvp in pairsToChange)
dictionary[kvp.Key] = "blue";
You can't modify a collection whilst you're enumerating over it (in a loop).
You'll need to add your changes to a collection, then change them separately. Something like:
var itemsToChange = dictionary
.Where(d => d.Value == "red")
.ToDictionary(d => d.Key, d => d.Value);
foreach (var item in itemsToChange)
{
dictionary[item.Key] = "blue";
}
If you want to replace all occurences of "red", you'll need to store the KeyValuePairs in a list or something like that:
var redEntries = dictionary.Where(e => e.Value == "red").ToList();
foreach (var entry in redEntries) {
dictionary[entry.Key] = "blue";
}
var dict = new Dictionary<string, string>()
{
{ "first", "green" },
{ "second", "red" },
{ "third", "blue" }
};
foreach (var key in dict.Keys.ToArray())
{
if (dict[key] == "red")
{
dict[key] = "blue";
}
}
You cannot modify the collection you are iterating over in a foreach loop. If you could do that, it would open up several problems, such as "Do I run it on this newly-added value too?"
Instead, you should do something like this:
foreach( string key in dictionary.Keys )
{
if( dictionary[key] == "red" )
{
dictionary[key] = "blue";
}
}
Objects in foreach loops are read-only.
Please read through this and this for more understanding.

Create a nested list from a flat list using Linq

I have a list of strings like
A01,B01 ,A02, B12, C15, A12, ...
I want to unflatten the list into List of lists or dicitionary of lists such that
all strings starting with the same letter are group together (using linq)
A -> A01 , A02 , Al2
B -> B01 , B12
C -> C15
or
A -> 01 , 02 , l2
B -> 01 , 12
C -> 15
For now I just iterate the list using for loop and add the values to the approp list from dictionary.
(may not be right!)
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
foreach( string str in stringList)
{
string key = str.Substring(0,1);
if (!dict.ContainsKey(key)){
dict[key] = new List<string>();
}
dict[key].Add(str);
}
Edit :
Oh sorry i forgot to add this ,
I have a list of Category objs , and these are Category names.
I need to retrieve something like Dictionary<string, List<Category>> , going forward i want to bind this to a nested list . (asp.net/ mvc )
Is there a better way to do the same using Linq?
It sounds like you want a Lookup, via the ToLookup extension method:
var lookup = stringList.ToLookup(x => x.Substring(0, 1));
A lookup will let you do pretty much anything you could do with the dictionary, but it's immutable after construction. Oh, and if you ask for a missing key it will give you an empty sequence instead of an error, which can be very helpful.
Coming from the chat room, try this. I know it's not the most elegant solution, there is probably better.
List<string> listOfStrings = {"A01", "B01", "A02", "B12", "C15", "A12"}.ToList();
var res = listOfStrings.Select(p => p.Substring(0, 1)).Distinct().ToList().Select(p =>
new {
Key = p,
Values = listOfStrings.Where(c => c.Substring(0, 1) == p)
}).ToList();
foreach (object el_loopVariable in res) {
el = el_loopVariable;
foreach (object x_loopVariable in el.Values) {
x = x_loopVariable;
Console.WriteLine("Key: " + el.Key + " ; Value: " + x);
}
}
Console.Read();
Gives the following output:
If you want to use dictionary, you may want this
List<String> strList = new List<String>();
strList.Add("Axxxx");
strList.Add("Byyyy");
strList.Add("Czzzz");
Dictionary<String, String> dicList = strList.ToDictionary(x => x.Substring(0, 1));
Console.WriteLine(dicList["A"]);

C# Dictionary to .csv

I have C# Dictionary and I want create a .csv file from it.
For example I have this dictionary:
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("0", "0.15646E3");
data.Add("1", "0.45655E2");
data.Add("2", "0.46466E1");
data.Add("3", "0.45615E0");
And I wanna this .csv file output:
0;0.15646E3;
1;0.45655E2;
2;0.46466E1;
3;0.45615E0;
How can I do this?
Maybe the easiest:
String csv = String.Join(
Environment.NewLine,
data.Select(d => $"{d.Key};{d.Value};")
);
System.IO.File.WriteAllText(pathToCsv, csv);
You'll need to add using LINQ and use at least .NET 3.5
Try the following
using (var writer = new StreamWriter(#"the\path\to\my.csv")) {
foreach (var pair in data) {
writer.WriteLine("{0};{1};", pair.Key, pair.Value);
}
}
Note: This will fail to work if the key or value elements can contain a ;. If so you will need to add an escaping mechanism to handle that
File.WriteAllLines(#"pathtocsv.csv", data.Select(x => x.Key + ";" + x.Value + ";")));
My dictionary was similar to the one in the question posed above (by user1387150) except the VALUE part was an array (of doubles, i.e.double[]).
Adjusting Jared's solution above, allows a Dictionary<string, double[]> to be written to csv as follows:
using (var writer = new StreamWriter(#"C:\path\test.csv"))
{
foreach (var pair in data)
{
writer.WriteLine("{0},{1};", pair.Key, String.Join(",", pair.Value.Select(x => x.ToString()).ToArray()));
}
}

Categories

Resources