Take count of repeating words in file - c#

I have code to take count of repeating words in file
Here it is
static void Main()
{
StreamReader f = new StreamReader(#"d:\C#\text.txt");
string s = f.ReadToEnd();
char[] separators = { };//here is symbols
List<string> words = new List<string>(s.Split(separators));
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (string w in words)
if (map.ContainsKey(w)) map[w]++; else map[w] = 1;
foreach (string w in map.Keys)
Console.WriteLine("{0}\t{l}", w.map[w]);
}
But in this row Console.WriteLine("{0}\t{l}", w.map[w]); I have this error.
Error CS1061 'string' does not contain a definition for 'map' and no extension method 'map' accepting a first argument of type 'string' could be found
How I can fix this error?

If I undertood what you wanted, this will help:
List<string> words = new List<string>() { "c#", "html", "web service", "c#", "c#" };
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (string w in words)
{
if (map.ContainsKey(w))
{
map[w] = map[w]+1;
}
else
{
map[w] = 1;
}
}
//to iterate through Dictionary<string, int> use this instead
foreach (KeyValuePair<string, int> entry in map)
{
Console.WriteLine($"{entry.Key}\t{entry.Value}");
}

Related

All the nested dictionaries holds the same value?

I'm trying to build this datastructure with a nested dictionary:
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
And then loop over the data structure and print out the values.
The first problem is, that all the nested dictionaries are the same {"C",123}.
I think it's because it is the same object, but I don't know how to overcome that. Can I dynamically create new objects in the loop ?
The other problem i face is in the loop where I try to print out the Values.
The compiler says that it can't convert Dictionary to Dictionary.
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
public static void Main()
{
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
Dictionary<string, int> DictOfData = new();
foreach (string i in liste)
{
DictOfData.Clear();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (Dictionary<string, int> i in DictOfDicts)
{
Console.WriteLine("Some result");
}
}
}
}
You declared DictOfData outside of the foreach loop. Then, all the operations inside the loop are done on the same object. So, you are clearing and filling the same dictionary object over and over again, on each loop iteration.
Just move you declaration of DictOfData to inside the loop, and you'll be good to go.
Bonus:
The whole operation you displayed in the questions can be done with just this:
liste.ToDictionary(x => x, x => new Dictionary<string, int>() { { x, 123 } })
var liste = new List<string>() { "A", "B", "C" };
var DictOfDicts = new Dictionary<string, Dictionary<string, int>>();
foreach (var i in liste)
{
// Create here a new DictOfData to add it to DicOfCicts.
var DictOfData = new Dictionary<string, int>();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
The structure of DicOfDicts is,
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
I've used a slightly older C# language specification for the answer, and made the type declarations more clear for you to understand.
List<string> list = new List<string>() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> parent = new Dictionary<string, Dictionary<string, int>>();
foreach (string i in list)
{
Dictionary<string, int> child = new Dictionary<string, int>();
child.Add(i, 123);
parent.Add(i, child);
}
foreach (KeyValuePair<string, Dictionary<string, int>> parentPair in parent)
{
Dictionary<string, int> childDictionary = parentPair.Value;
foreach (var childPair in childDictionary)
{
Console.WriteLine(childPair.Value);
}
}
It's a very easy exercise to fix your code. Simply replace the DictOfData.Clear(); with the declaration of DictOfData itself. In other words, move the line Dictionary<string, int> DictOfData = new(); into the loop. That way you have a fresh instance of the nested dictionary rather than reusing the old one.
Try this code:
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
foreach (string i in liste)
{
Dictionary<string, int> DictOfData = new();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (KeyValuePair<string, Dictionary<string, int>> i in DictOfDicts)
{
Console.WriteLine($"[{i.Key},{String.Join(",", i.Value.Select(x => $"[{x.Key},{x.Value}]"))}]");
}

Need to check a key in a dictionary for the letters of a string

So I have a dictionary and need to check each key entry to see if it contains a series of letters in a string(lets call this LETTERS). If the key has any letters that LETTERS does not, or it has more of a letter than LETTERS has, it has to be removed.(LETTERS is not known beforehand)
This is the code involved
Dictionary<string, int> wordHolder = new Dictionary<string, int>();
string LETTERS = Console.ReadLine();
for (int i = 0; i < LETTERS.Count(); i++)
{
for (int j = 0; j < wordHolder.Count; j++)
{
}
}
I think i have it this time if you still need an answer
The below has 5 keys... 3 of which can not be created from the contents of "LETTERS".
Dictionary<string, int> wordHolder = new Dictionary<string, int>();
wordHolder.Add("CEFBA",1);
wordHolder.Add("ZDFEEG",2);
wordHolder.Add("TYHRFG", 3);
wordHolder.Add("FFFFBBDD", 4);
wordHolder.Add("PCDATTY", 5);
var keysToRemove = new List<string>();
string myLetters = "ABCDEF";
var myLettersArray = myLetters.ToCharArray();
foreach (var keyToCheck in wordHolder)
{
var keyCannotBeCreatedFromLetters = false;
var keyArray = keyToCheck.Key.ToCharArray();
foreach (var letterExists in
from keyLetterToCheck in keyArray
where !keyCannotBeCreatedFromLetters
select myLettersArray.Any(a => a == keyLetterToCheck)
into letterExists
where !letterExists select letterExists)
{
keysToRemove.Add(keyToCheck.Key);
keyCannotBeCreatedFromLetters = true;
}
}
foreach (var key in keysToRemove)
{
wordHolder.Remove(key);
}
It correctly identifies the 2nd, 3rd and 5th key as not creatable.
Below is the same logic but as foreach loops. I find this often useful so you can see whats happening internally.
foreach (var keyToCheck in wordHolder)
{
var keyCannotBeCreatedFromLetters = false;
var keyArray = keyToCheck.Key.ToCharArray();
foreach (var keyLetterToCheck in keyArray)
{
if (keyCannotBeCreatedFromLetters)
continue;
var letterExists = myLettersArray.Any(a => a == keyLetterToCheck);
if (letterExists) continue;
keysToRemove.Add(keyToCheck.Key);
keyCannotBeCreatedFromLetters = true;
}
}
Assuming you want to return any KeyValuePair which Key contains all letter inside LETTERS.
It would look like this:
// Assuming
// Dictionary<string, int> wordHolder = new Dictionary<string, int>(); // Something
// string LETTERS = ""; // Something
List<char> listLettersToHave = LETTERS.ToList();
Dictionary<string, int> researchResult = new Dictionary<string, int>();
foreach (KeyValuePair<string, int> pair in wordHolder)
{
List<char> listLettersYouHave = pair.Key.ToList();
bool ok = true;
// If not the same count go to next KeyValuePair
if (listLettersToHave.Count != listLettersYouHave.Count)
continue;
foreach (char toCheck in listLettersToHave)
{
// Search first occurence
if (!listLettersYouHave.Contains(toCheck))
{
ok = false;
break;
}
// Remove first occurence
listLettersYouHave.Remove(toCheck);
}
if (ok)
// If all letters contained then Add to result
researchResult.Add(pair.Key, pair.Value);
}
// if it's a function
// return researchResult;
It's an example and you can improve it but the idea is here.
EDIT :
If the dictionnary have for keys : abc, cbda, dca
An input of bac
The results key would be : abc
The solution is case sensitive but a .ToUpper() will solve the problem.
Using the previous example, if you want cbda to match you can remove the check on Count.

Loop through multiple dictionaries

I have 6 dictionaries. I want to compare another dictionaries against each one of them and see what dictionaries contains what strings. Is it possible to do with a foreach loop?
static Dictionary<string, int> d = new Dictionary<string, int>();
static Dictionary<string, double> dNL = new Dictionary<string, double>();
static Dictionary<string, double> dDE = new Dictionary<string, double>();
static Dictionary<string, double> dFR = new Dictionary<string, double>();
static Dictionary<string, double> dSP = new Dictionary<string, double>();
static Dictionary<string, double> dEN = new Dictionary<string, double>();
static Dictionary<string, double> dIT = new Dictionary<string, double>();
foreach (var f in d)
{
if (dNL.ContainsKey(f.Key))
{
//add to a numeric?
}
if (dDE.ContainsKey(f.Key))
{
//add to a numeric?
}
}
something like this?
what I currently have (and not working like intended):
// need to find a better solution
foreach (var f in d)
{
if (dNL.ContainsKey(f.Key))
{
dNLtotaal++;
}
}
foreach (var f in d)
{
if (dDE.ContainsKey(f.Key))
{
dDEtotaal++;
}
}
foreach (var f in d)
{
if (dFR.ContainsKey(f.Key))
{
dFRtotaal++;
}
}
foreach (var f in d)
{
if (dSP.ContainsKey(f.Key))
{
dSPtotaal++;
}
}
foreach (var f in d)
{
if (dEN.ContainsKey(f.Key))
{
dENtotaal++;
}
}
foreach (var f in d)
{
if (dIT.ContainsKey(f.Key))
{
dITtotaal++;
}
}
// NEED A MUCH BETTER SOLUTION
List<int> totaleD = new List<int>();
totaleD.Add(dNLtotaal);
totaleD.Add(dDEtotaal);
totaleD.Add(dFRtotaal);
totaleD.Add(dSPtotaal);
totaleD.Add(dENtotaal);
totaleD.Add(dITtotaal);
int max = !totaleD.Any() ? -1 : totaleD.Select((value, index) => new { Value = value, Index = index }).Aggregate((a, b) => (a.Value > b.Value) ? a : b).Index;
var maxIndex = totaleD.IndexOf(totaleD.Max());
Console.WriteLine(maxIndex);
You can do something like this:
var items = d.Keys;
var dictionaries = new[] { dNL, dDE, dFR, dSP, dEN, dIT };
var result = dictionaries.Select((d, index) =>
new {
Index = index,
Matches = items.Count(i => d.ContainsKey(i))
})
.OrderByDescending(i => i.Matches)
.Select(i => i.Index)
.FirstOrDefault();
Which gives you the index of the dictionary with the most matches
You could use lambda expressions to get the desired results. In following example, I tried to use two dictionaries:
int dNLtotaal = 0;
Dictionary<string, double> dNL = new Dictionary<string, double>();
Dictionary<string, double> dDE = new Dictionary<string, double>();
dNL.Keys.Where(k => dDE.ContainsKey(k)).ToList().ForEach(k => dNLtotaal++);
Hope it helps
Why not to have 1 Dictionary instead of 6? And keep there a pair [string, List[SomeObject]] where SomeObject is a class like
class SomeObject
{
public Enum Type;//dNL, dDE etc
public double Value;
}

Trying to compare two lists c# - Should work?

I have a method that looks like this:
GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
Firstly, the method creates a new List<string> with all the items from ImportData<string, bool> that have the value true and can be found in string[] ItemsToCompare
Secondly, I would like to compare the new List<string> with the List from AllDrawings<string, List<string>>. The method is in the end supposed to return a string with the key from AllDrawings<string>, List<String>> where the two lists match.
I have now spent a lot of hours trying to figure this out myself and also tried every answer I could find to similar questions here on Stackoverflow but with no luck.
Below is the full code for my method. As mentioned above I've tried a lot of different methods to compare the lists but the one following below is the latest try.
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
string FinalDrawing = "";
try
{
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var match = AllCorrect.SequenceEqual(DrawItem.Value);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return FinalDrawing;
}
My problem is that the return value from var match = AllCorrect.SequenceEqual(DrawItem.Value); is false and therefore the FinalDrawing is never set.
All answers are very appreciated.
Thanks in advance!
Ok.. I already said that in comments, but just to make sure that you don't get yelled at too much for not-using-linq and such:
your program seems correct up to the point you told us.
Here's a simple test. I provided some stub data that cover all things that you seem to check:
only true things from importedata
only things that are listed in itemstocompare
input lists are not sorted
-> http://rextester.com/HAE73942
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
// your original function, nothing changed
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
string FinalDrawing = "";
try
{
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var match = AllCorrect.SequenceEqual(DrawItem.Value);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return FinalDrawing;
}
public static void Main(string[] args)
{
var allDrawings = new Dictionary<string, List<string>>();
allDrawings.Add("aaa", new List<string>{ "a03", "a01", "a02" }); // originally unsorted
allDrawings.Add("bbb", new List<string>{ "b03", "b01", "b02" }); // originally unsorted
allDrawings.Add("ccc", new List<string>{ "c03", "c01", "c02" }); // originally unsorted
var import = new Dictionary<string, bool>();
import.Add("b01", false); // falsey
import.Add("a05", true); // not in comparison
import.Add("a03", true);
import.Add("c01", false); // falsey
import.Add("a02", true);
import.Add("a04", true); // not in comparison
import.Add("a01", true);
var toCompare = new string[9];
toCompare[0]="a01"; toCompare[1]="a02"; toCompare[2]="a03";
toCompare[3]="b01"; toCompare[4]="b02"; toCompare[5]="b03";
toCompare[6]="c01"; toCompare[7]="c02"; toCompare[8]="c03";
var result = GetDrawing(allDrawings, import, toCompare);
Console.WriteLine("Result: " + result);
}
}
it works fine and prints aaa as it should.
This means that you had to have overlooked something in the input data. Maybe some strings are uppercase/lowercase? Maybe some strings have whitespaces inside and others not?
This code :
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
Can be reduced to :
List<string> AllCorect = ImportData.Where(vp =>
ItemsToCompare.Contains(vp.Key) && vp.Value).Select(vp => vp.Key).OrderBy(vp => vp).ToList();
To solve the second problem you can do :
return AllDrawings.First(l => l.Value.OrderBy(l2 => l2).SequenceEqual(AllCorect)).Key;
P.S.
If First() always throws an exception then it suggests that problem lays in how this lists are filled with values and this is a different question.
Example :
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
List<string> AllCorect = ImportData.Where(vp =>
ItemsToCompare.Contains(vp.Key) && vp.Value).Select(vp => vp.Key).OrderBy(vp => vp).ToList();
return AllDrawings.First(l => l.Value.OrderBy(l2 => l2).SequenceEqual(AllCorect)).Key;
}
static void Main(string[] args)
{
List<string> list1 = new List<string>() { "one", "two", "three" };
List<string> list2 = new List<string>() { "five", "six", "seven" };
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>()
{
{"first", list1}, {"second", list2}
};
string[] itemsToCompare = { "one", "two", "three" };
var dict2 = new Dictionary<string, bool>()
{
{"one", true},
{"two", true},
{"three", true}
};
var result = GetDrawing(dict, dict2, itemsToCompare);
Console.WriteLine(result);
}
Output : first
If the strings really match also for casing your code would be correct. I propose you inspect your string sequences - create an readable string and add appropriate break points. Also try to sort case-insensitive if that is what is missing here
AllCorrect.Sort(StringComparer.InvariantCultureIgnoreCase);
var AllCorrectInfo = string.Join(", ", AllCorrect.ToArray());
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var DrawItemInfo = string.Join(", ", DrawItem.Value.ToArray());
var match = AllCorrect.SequenceEqual(DrawItem.Value, StringComparer.InvariantCultureIgnoreCase);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}

Read Array of Arrays

I have a block of C# that looks like this
public static string[,] FileTypesDict = new string[,] {
{"txt", "ReadFile"},
{"doc", "ReadMSOfficeWordFile"},
{"docx", "ReadMSOfficeWordFile"},
{"xls", "ReadMSOfficeExcelFile"},
{"xlsx", "ReadMSOfficeExcelFile"},
{"pdf", "ReadPDFFile"},
};
I would like to use this inside another function like this...
static void FindFiles() {
foreach (string type[] in FileTypesDict) {
// Find all files with extension
string[] files = Directory.GetFiles(FilePath, type[0]);
// To be used in another fun way, the longer description
string filetype = type[1]
}
}
That, of course, doesn't work... It seems to only work when I do this -->
static void FindFiles() {
foreach (string type in FileTypesDict) {
Console.WriteLine(type);
}
}
That will print each part of each array, like this -->
txt
ReadFile
doc
ReadMSOfficeWordFile
docx
ReadMSOfficeWordFile
xls
ReadMSOfficeExcelFile
xlsx
ReadMSOfficeExcelFile
pdf
ReadPDFFile
I'd basically like to look over the array of arrays and use each array inside of the loop...
You should be using a Dictionary for this, as it makes things much neater and readable.
You could do this:
Dictionary<string, string> fileTypes = new Dictionary<string, string>()
{
{"txt", "ReadFile"},
{"doc", "ReadMSOfficeWordFile"},
{"docx", "ReadMSOfficeWordFile"},
{"xls", "ReadMSOfficeExcelFile"},
{"xlsx", "ReadMSOfficeExcelFile"},
{"pdf", "ReadPDFFile"}
};
foreach (KeyValuePair<string, string> file in fileTypes)
{
Console.WriteLine(String.Format("{0} - {1}", file.Key, file.Value));
}
Or if you wanted to make the value a collection of string, you could do this:
Dictionary<string, List<string>> fileTypesWithList = new Dictionary<string, List<string>>()
{
{ "txt", new List<string>() { "Some", "Other", "Data" }}
};
foreach (KeyValuePair<string, List<string>> file in fileTypesWithList)
{
foreach (string s in file.Value)
{
Console.WriteLine(String.Format("{0} - {1}", file.Key, s));
}
}
The solution to your question is to define FileTypesDict as string[][]. Now I agree with the comments that the way you should do it is with a Dictionary.
see here: http://msdn.microsoft.com/en-us/library/2s05feca.aspx
static void FindFiles()
{
for (int i = 0; i < FileTypesDict.Length; i++)
{
var fileType = FileTypesDict[i, 0];
var action = FileTypesDict[i, 1];
string[] files = Directory.GetFiles(FilePath, fileType);
}
}

Categories