Compare 1st then 2nd then 3rd column of Text File - c#

I'm making a Quizlet Type program and need help comparing text files. I have written
Hello, Hallo
Dog, Hund
Cat, Katze
That is my Text file. I want my program to compare 1st column
Hello, Hallo
And then after that comparison
Dog, Hund
and after that
Cat, Katze
As you see here I wrote code that compares the first row to the second row. But after that, it just doesn't compare to the second column of the file. I need help comparing to 2nd column then 3rd etc.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test32
{
class Program
{
static void Main(string[] args)
{
string filepath = #"C:\Users\akred\Desktop\testfall2\testfall2\Eng.txt";
bool wantstoguess = true;
int attempt = 0;
bool win = false;
int row = 0;
List<engword> word = new List<engword>();
List<string> lines = File.ReadAllLines(filepath).ToList();
foreach (var line in lines)
{
string[] entries = line.Split(',');
engword newWord = new engword();
//Ew = Englisches Wort
//REw = Richtig Englisches Wort bzw richtige übersetzung
newWord.Ew = entries[0].Trim();
newWord.REw = entries[1].Trim();
word.Add(newWord);
}
foreach (var engword in word)
{
do
{
do
{
Console.WriteLine("What is " + $"{engword.Ew }" + " in English");
attempt++;
string guessed = Console.ReadLine();
try
{
if (guessed == $"{ engword.REw }")
{
Console.WriteLine("Correct");
win = true;
++row;
}
else if ($"{ engword.REw }" != guessed)
{
Console.WriteLine("Incorrect");
}
}
catch
{
Console.WriteLine("Please Write a word");
}
} while (win == false);
if (win == true)
{
Console.WriteLine("You gave guessed it!");
Console.Write("It took you " + attempt + " attempts!");
Console.ReadLine();
}
Console.Write("Do you want to continue? [Yes/No]?");
string answer = Console.ReadLine();
if (answer == "Yes")
wantstoguess = true;
win = false;
if (answer == "No")
wantstoguess = false;
} while (wantstoguess == true);
}
Console.ReadLine();
}
}
}

It seems, that you are looking for a Dictionary, Dictionary<string, string>, e.g.
using System.Linq;
...
Dictionary<string, string> EnToDe = File
.ReadLines(filepath)
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select(line => line.Split(','))
.ToDictionary(pair => pair[0].Trim(),
pair => pair[1].Trim(),
StringComparer.OrdinalIgnoreCase);
You can easily create reversed German - English dictionary as well:
Dictionary<string, string> DeToEn = EnToDe
.ToDictionary(pair => pair.Value,
pair => pair.Key,
StringComparer.OrdinalIgnoreCase);
Now you can easily get words
List<string> englishWords = EnToDe.Keys.ToList();
List<string> deutschWords = EnToDe.Keys.ToList();
and translation
string english = "CAT";
if (EnToDe.TryGetValue(english, out var deutsch))
Console.Write($"English \"{english}\" is German \"{deutsch}\"");
else
Console.Write($"Sorry, Engish \"{english}\" is not found in the dictionary");
Edit: If you want to implement some kind of test where student must translate each word from German into English, you can try a simple loop. First we prepare the words:
string[] germanWords = DeToEn
.Keys
.OrderBy(x => Guid.NewGuid()) // Shuffle
.ToArray();
// words which are difficult to learn and thus should be tested again
HashSet<string> wordsToRepeat = new HashSet<string>();
Then loop over these words:
foreach (string word in germanWords) {
int attempt = 0;
while (true) {
attempt += 1;
Console.WriteLine($"What is {word} in English?");
string guessed = Console.ReadLine().Trim();
if (string.Equals(guessed, DeToEn[word], StringComparison.OrdinalIgnoreCase)) {
Console.WriteLine("You gave guessed it!");
Console.WriteLine($"It took you {attempt} attempts!");
break;
}
Console.WriteLine("Incorrect");
// If the word is too difficult to translate, it should appear again
if (attempt >= 3) // let word be difficult if it takes 3+ attempt to guess it
wordsToRepeat.Add($"{word},{DeToEn[word]}");
}
Console.Write("Do you want to continue? [Yes/No]?");
string answer = Console.ReadLine().Trim();
if (string.Equals(answer, "N", StringComparison.OrdinalIgnoreCase) ||
string.Equals(answer, "NO", StringComparison.OrdinalIgnoreCase))
break;
}
File.WriteAllLines("c:\WordsToRepeat.txt", wordsToRepeat);

The way your code is structured is a bit confusing, but if you see what it is actually doing it will be
for each word
{
until the user opts out
{
until the answer is correct
{
try to guess
}
}
}
Which means you never get to the next word unless the user says they don't want to continue. A better way would be do something like
for each word
{
until the answer is correct
{
try to guess
}
if(does not want to continue)
break;
}
Here break will get you out of the for each word loop
UPDATE
If I understood correctly what you're trying to achieve, you should end up with something like
foreach (var engword in word)
{
// do --> remove this
// {--> remove this
do
{
...
} while (win == false);
if (win == true)//this check is unnessesary, you won't get here unless win is true
{
Console.WriteLine("You gave guessed it!");
Console.Write("It took you " + attempt + " attempts!");
Console.ReadLine();
}
Console.Write("Do you want to continue? [Yes/No]?");
string answer = Console.ReadLine();
//Add this
if (answer == "No")
{
Console.Write("Okay, bye!");
break;
}
win = false;
// if (answer == "No")--> remove this
// wantstoguess = false;--> remove this
//} while (wantstoguess == true); --> remove this
}

You should use Dictionary<string, string> instead of List. Then key of dictionary will be english word and value will be german word.
After you build dictionary from txt file you have to loop the dictionary keys (english words) and you have to compare user's input with dictionary value of current key.
// firstly you have to build dictionary similar this
string filepath = #"C:\Users\akred\Desktop\testfall2\testfall2\Eng.txt";
Dictionary<string, string> myDict = File
.ReadLines(filepath)
.Where(line => !string.IsNullOrWhiteSpace(line))
.Select(line => line.Split(','))
.ToDictionary(words => words[0].Trim(), words => words[1].Trim());
foreach(var item in myDict)
{
// here you have to implement loop for user's input and comparing with value
Console.WriteLine($"What is { item.key } in english?");
string guessed = Console.ReadLine();
if (guessed == item.value)
{
// OK
}
else
{
// fail
}
}

Related

Don't know how to print a dictionary which has a list inside

This is the input I'm using for the current case:
Like Krisi shrimps
Like Krisi soup
Like Penelope dessert
Like Misho salad
stop
This is my whole code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace GuestsFoods._1
{
class Program
{
static void Main(string[] args)
{
string input = Console.ReadLine();
//input:
//Like Krisi shrimps
//Like Krisi soup
//Like Penelope dessert
//Like Misho salad
//stop
int unliked = 0;
Dictionary<string, List<string>> guestsFoods = new Dictionary<string, List<string>>();
// Key: Krisi, Value: shrimps, soup
// Key: Penelope, Value: dessert
// Key: Misho , Value: salad
while(input != "stop")
{
List<string> inputs = input.Split(" ").ToList();
if (inputs[0] == "Like")
{
if (guestsFoods.ContainsKey(inputs[1]))
{
guestsFoods[inputs[1]].Add(inputs[2]);
}
else
{
guestsFoods.Add(inputs[1], new List<string> {inputs[2]});
}
}
else if (inputs[0] == "Dislike")
{
if (guestsFoods!.ContainsKey(inputs[1]))
{
Console.WriteLine($"{inputs[1]} is not at the party");
}
else
{
guestsFoods[inputs[1]].Remove(inputs[2]);
unliked++;
}
}
input = Console.ReadLine();
}
//foreach (KeyValuePair<string, List<string>> data in guestsFoods)
//{
//Console.WriteLine(data.Key + " -> ");
//foreach (string food in guestsFoods[new List<string>[]])
//{
//Console.Write("");
//}
//}
}
}
}
As you can see I am using the Dictionary.Key to store the person's name and the Dictionary.Value, which is a list, to store the foods they like.
I want my output to be printed like this:
Key - Value1, Value2, Value3 ... ValueN
But I don't know how to do it. As you can see by the comments I tried to do it myself, but I can't think of the logic required.
In your (commented out) loop, if data.Key is the string for the dictionary entry, then data.Value is the List<string>. You can loop over that list:
foreach (string val in data.Value)
{
Console.Write(val);
}
Maybe add some formatting:
foreach (string val in data.Value)
{
Console.Write($"{val}, ");
}
Which you'll then find leaves you with a trailing comma. You can add logic to conditionally show the comma. But fortunately we don't need to go down this road, because string.Join makes this even easier. In fact, you don't need a loop at all once you use that:
Console.Write(string.Join(", ", data.Value));
Which would combine all the strings in the list with ", " as a delimiter.

How to sort a dictionary in C# .net

I need to make a frequency analysis console program using c#. It has to show the 10 most frequent letters from a textfile. I have managed to display the first 10 letters read by the program and the frequency of each character. I, however, don't know how to sort the dictionary. This is the code I have so far.
I must also give the user the option to the frequency analysis in case sensitive mode (as it is right now) and case insensitive. Help with this issue will also be appreciated. Thank You!
static void Main(string[] args)
{
// 1.
// Array to store frequencies.
int[] c = new int[(int)char.MaxValue];
// 2.
// Read entire text file.
// string root = Server.MapPath("~");
// string FileName = root + "/App_Data/text.txt";
//string s = File.ReadAllText(FileName);
foreach (string line in File.ReadLines(#"c:\Users\user\Documents\Visual Studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\App_Data\text.txt", Encoding.UTF8)) {
var fileStream = new FileStream(#"c:\Users\user\Documents\Visual Studio 2015\Projects\ConsoleApplication1\ConsoleApplication1\App_Data\text.txt", FileMode.Open, FileAccess.Read);
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
string line2;
while ((line2 = streamReader.ReadLine()) != null)
{
// process the line
// 3.
// Iterate over each character.
foreach (char t in line)
{
// Increment table.
c[(int)t]++;
}
// 4.
// Write all letters found.
int counter = 0;
for (int i = 0; i < (int)char.MaxValue; i++)
{
if (c[i] > 0 && counter < 11 &&
char.IsLetterOrDigit((char)i))
{
++counter;
Console.WriteLine("Letter: {0} Frequency: {1}",
(char)i,
c[i]);
}
}
}
}
Console.ReadLine();
}
}
If all you want to do is to found frequencies, you don't want any dictionaries, but a Linq. Such tasks are ones Linq has been designed for:
...
using System.Linq;
...
static void Main(string[] args) {
var result = File
.ReadLines(#"...", Encoding.UTF8)
.SelectMany(line => line) // string into characters
.Where(c => char.IsLetterOrDigit(c))
.GroupBy(c => c)
.Select(chunk => new {
Letter = chunk.Key,
Count = chunk.Count() })
.OrderByDescending(item => item.Count)
.ThenBy(item => item.Letter) // in case of tie sort by letter
.Take(10)
.Select(item => $"{item.Letter} freq. {item.Count}"); // $"..." - C# 6.0 syntax
Console.Write(string.Join(Environment.NewLine, result));
}
I like #Dmitry Bychenko's answer because it's very terse. But, if you have a very large file then that solution may not be optimal for you. The reason being, that solution has to read the entire file into memory to process it. So, in my tests, I got up to around 1GB of memory usage for a 500MB file. The solution below, while not quite as terse, uses constant memory (basically 0) and runs as fast or faster than the Linq version in my tests.
Dictionary<char, int> freq = new Dictionary<char, int>();
using (StreamReader sr = new StreamReader(#"yourBigFile")) {
string line;
while ((line = sr.ReadLine()) != null) {
foreach (char c in line) {
if (!freq.ContainsKey(c)) {
freq[c] = 0;
}
freq[c]++;
}
}
}
var result = freq.Where(c => char.IsLetterOrDigit(c.Key)).OrderByDescending(x => x.Value).Take(10);
Console.WriteLine(string.Join(Environment.NewLine, result));
It would be easier to use the actual Dictionary type in C# here, rather than an array:
Dictionary<char, int> characterCountDictionary = new Dictionary<char, int>();
You add a key if it doesn't exist already (and insert a value of 1), or you increment the value if it does exist. Then you can pull out the keys of your dictionary as a list and sort them, iterating to find the values. If you do case insensitive you'd just convert all upper case to lower case before inserting into the dictionary.
Here's the MSDN page for the examples for Dictionary: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx#Examples

Creating lists with loops by an user in C#

So I want to make a list of names. I want this list to go on until user inputs 0 to quit, after user types 0 I want all names to be displayed. You probably see what I'm trying to do from the code below...that "typedName" is there just so you see what I'm trying to do.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<string> names = new List<string>();
Console.WriteLine("Type in 0 to end.");
bool over = false;
while (over != true)
{
names.Add(Console.ReadLine());
if(typedName == "0")
{
over = true;
}
}
Console.WriteLine("Entered names : ");
names.ForEach(Console.WriteLine);
Console.ReadLine();
}
}
}
First you need the typedName to be captured and then check if it is equal to 0.
if it is not add it to the list
List<string> names = new List<string>();
Console.WriteLine("Type in 0 to end.");
while (true)
{
var typedName = Console.ReadLine();
if (typedName.Equals("0"))
{
break;
}
names.Add(typedName);
}
Console.WriteLine("Entered names : ");
foreach(var name in names)
{
Console.WriteLine(name);
}
Console.ReadLine();
if(typedName == "0")
Well, what is typedName? Or what should it be? I suspect it should be the input entered by the user, something like this:
var typedName = Console.ReadLine();
You can then add it to the list by using that variable:
names.Add(typedName);
And compare it with "0" as you already do, etc.
your code is not complete that is why is not working...
you are missing the most important part:
populate the list if and only if typedName != "0"
while (!over)
{
var typedName =Console.ReadLine();
if(typedName == "0")
{
over = true;
}else
{
Console.WriteLine("Enter a name... ");
names.Add(Console.ReadLine());
}
...
}

Validating String in C#

Hi so im trying to validate my string here so that it does not allow any input that starts with: "911" so if you type: "9 11", "91 1", "9 1 1" it should go through my if statement. It works with "911" but not the others, here's my code:
using System;
using System.Collections.Generic;
namespace Phone_List
{
class Program
{
static void Main(string[] args)
{
var phoneList = new List<string>();
string input;
Console.WriteLine("Input: ");
while ((input = Console.ReadLine()) != "")
{
phoneList.Add(input);
for (int i = 0; i < phoneList.Count; i++)
{
if (phoneList[i].Substring(0, 3) == "911")
{
input.StartsWith("9 11");
input.StartsWith("9 1 1");
input.StartsWith("91 1");
Console.WriteLine("NO");
Console.ReadLine();
return;
}
else
{
Console.WriteLine("YES");
Console.ReadLine();
return;
}
}
}
}
}
}
As you can see I am trying to use "input.StartsWith("9 11");" but it does not work...
You could use the Replace method of String; the condition you describe can be formulated as follows.
input.Replace(" ", "").StartsWith("911")
Use regular expressions for checks like this.
For example:
Regex.IsMatch(input, "^\\s*9\\s*1\\s*1");
This regex matches all strings that include whitespaces in front of and between "911".
Use the following to check if the string starts with "911":
First create a copy from the input string but without any white spaces:
string input_without_white_spaces =
new string(input.ToCharArray().Where(x => !char.IsWhiteSpace(x)).ToArray());
Then you can check if the string starts with 911 like this:
if (input_without_white_spaces.StartsWith("911"))
{
...
}
bool valid = s.StartsWith("911") ||
!string.Join("",s.Split()).StartsWith("911");

Dictionary with multiple keys isn't working as expected

I'm making a console program where I've got multiple values mapped to dictionary keyLookup. I'm using if commands that use the key to output some console.writeline = ("stuff"); but it only works if I have the value and the key the same (in the dictionary). I don't know why this is. I've been mucking about with list and foreach and some variables trying to figure out what I've done wrong but even though it continues to work how it works now it still doesn't work how I want.
Also if I have a word in my console.readline(); that isn't in my dictionary the whole thing crashes. Which I don't want, and I'm not sure of why its doing that either as at some point it didn't. Also my mathFunction dictionary works just how I want my keyLookup dictionary to work. Though I think the difference is in how I'm using a list to cross reference through keyLookup.
class MainClass
{
public static string Line;
static string foundKey;
public static void Main (string[] args)
{
while (true)
{
if (Line == null)
{Console.WriteLine ("Enter Input"); }
WordChecker ();
}
}
public static void WordChecker()
{
string inputString = Console.ReadLine ();
inputString = inputString.ToLower();
string[] stripChars = { ";", ",", ".", "-", "_", "^", "(", ")", "[", "]",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "\n", "\t", "\r" };
foreach (string character in stripChars)
{
inputString = inputString.Replace(character, "");
}
// Split on spaces into a List of strings
List<string> wordList = inputString.Split(' ').ToList();
// Define and remove stopwords
string[] stopwords = new string[] { "and", "the", "she", "for", "this", "you", "but" };
foreach (string word in stopwords)
{
// While there's still an instance of a stopword in the wordList, remove it.
// If we don't use a while loop on this each call to Remove simply removes a single
// instance of the stopword from our wordList, and we can't call Replace on the
// entire string (as opposed to the individual words in the string) as it's
// too indiscriminate (i.e. removing 'and' will turn words like 'bandage' into 'bdage'!)
while ( wordList.Contains(word) )
{
wordList.Remove(word);
}
}
// Create a new Dictionary object
Dictionary<string, int> dictionary = new Dictionary<string, int>();
// Loop over all over the words in our wordList...
foreach (string word in wordList)
{
// If the length of the word is at least three letters...
if (word.Length >= 3)
{
// ...check if the dictionary already has the word.
if ( dictionary.ContainsKey(word) )
{
// If we already have the word in the dictionary, increment the count of how many times it appears
dictionary[word]++;
}
else
{
// Otherwise, if it's a new word then add it to the dictionary with an initial count of 1
dictionary[word] = 1;
}
}
List<string> dicList = new List<string>();
dicList = dictionary.Keys.ToList ();
Dictionary<string, string> keyLookup = new Dictionary<string, string>();
keyLookup["hey"] = "greeting";
keyLookup["hi"] = "greeting";
keyLookup["greeting"] = "greeting";
keyLookup["math"] = "math";
keyLookup["calculate"] = "math";
keyLookup["equation"] = "math";
foundKey = keyLookup[word];
List<string> keyList = new List<string>();
foreach (string keyWord in dicList)
{
if(keyWord == foundKey)
{keyList.Add (keyWord); }
}
foreach (string mKey in keyList)
{
if(mKey == "greeting")
{Greetings ();}
if (mKey == "math")
{Math ();}
}
}
}
public static void Math()
{
Console.WriteLine ("What do you want me to math?");
Console.WriteLine ("input a number");
string input = Console.ReadLine ();
decimal a = Convert.ToDecimal (input);
Console.WriteLine("Tell me math function");
string mFunction = Console.ReadLine();
Console.WriteLine ("tell me another number");
string inputB = Console.ReadLine();
decimal b = Convert.ToDecimal (inputB);
Dictionary<string, string> mathFunction = new Dictionary<string, string>();
mathFunction["multiply"] = "multiply";
mathFunction["times"] = "multiply";
mathFunction["x"] = "multiply";
mathFunction["*"] = "multiply";
mathFunction["divide"] = "divide";
mathFunction["/"] = "divide";
mathFunction["subtract"] = "subtract";
mathFunction["minus"] = "subtract";
mathFunction["-"] = "subtract";
mathFunction["add"] = "add";
mathFunction["+"] = "add";
mathFunction["plus"] = "add";
string foundKey = mathFunction[mFunction];
if (foundKey == "add")
{
Console.WriteLine (a + b);
}
else if (foundKey == "subtract")
{
Console.WriteLine (a - b);
}
else if (foundKey == "multiply")
{
Console.WriteLine (a * b);
}
else if (foundKey == "divide")
{
Console.WriteLine (a / b);
}
else
{
Console.WriteLine ("not a math");
}
}
public static void Greetings()
{
Console.WriteLine("You said hello");
}
}'
You should iterate through the dictionary differently (Dont use ToList-Function).
Try this instead:
foreach (KeyValuePair kvp (Of String, String) In testDictionary)
{
Debug.WriteLine("Key:" + kvp.Key + " Value:" + kvp.Value);
}
And your application is crashing if the word doesn't match, because of this code (You're not creating a new entry that way):
// Otherwise, if it's a new word then add it to the dictionary with an initial count of 1
dictionary[word] = 1;
EDIT: I was wrong about that dictionary[word] = 1 would not create a new element. It's perfectly fine like this.
foundKey = keyLookup[word];
If word doesn't exist in keyLookup then it will crash.
string foundKey = mathFunction[mFunction];
if mFunction doesn't exist in mathFunction then it will crash.
If you're trying to make this a "conversational" program, then the word look-up is the most important part. You don't use predicates or LINQ, both can make string functions extremely easy. Currently you use a Dictionary. Why not use Lists for each keyword?
List<string> GreetingKeywords;
GreetingKeywords.Add("hello"); // ...
List<string> MathKeywords;
MathKeywords.Add("math"); // ...
foreach (var word in dicList)
{
if (GreetingKeywords.Contains(word))
{ Greetings(); }
if (MathKeywords.Contains(word))
{ Maths(); }
}
I'd suggest you read up on predicate and List/Dictionary functions such as Find, IndexOf, etc. etc. That knowledge is invaluable to C#.

Categories