Comparing characters of a list of arrays - c#

This is the exercise that I have to deal with:
You are given a word and a list of words. Your task is to check
whether all the words from the list are anagrams of the word. Input
Read from the standard input
On the first line, find W - the word to check against; On the second
line, find N - the number of words in the list of words WORDS; On the
next N lines, the words from WORDS; Output Print to the standard
output
For each word from WORDS print either: "Yes", if the word is an
anagram of W; "No", if the word is NOT an anagram of W;
And this is my code:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
string word1 = Console.ReadLine();
char[] mainWord = word1.ToLower().ToCharArray();
Array.Sort(mainWord);
int numberOfWords = int.Parse(Console.ReadLine());
List<Array> anagramWords = new List<Array>();
for (int i = 0; i < numberOfWords; i++)
{
string wordForList = Console.ReadLine();
char[] wordCharacters = wordForList.ToLower().ToCharArray();
Array.Sort(wordCharacters);
anagramWords.Add(wordCharacters);
}
foreach(object word in anagramWords)
{
if (word == mainWord)
{
Console.WriteLine("Yes");
}
else
{
Console.WriteLine("No");
}
}
}
}
For some reason, the answer that I get is always No.

if (word == mainWord)
doesn't compare the content of the word array with the content of the mainWord array.
Array variables are references types, or, in other words, they just contain the reference to the memory area where the elements of the array are really stored.
So if you compare the two arrays in that way you are comparing
two values (two references) that point to the memory area where the respective elements are stored. Of course these values are different because, even if the arrays contain the same characters, the elements are stored in different memory areas.
To solve your problem a different approach is needed.
Something like this should work
static void Main()
{
string word1 = Console.ReadLine();
IEnumerable<char>mainWord = word1.ToLower().OrderBy(w => w);
int numberOfWords = int.Parse(Console.ReadLine());
List<IEnumerable<char>> anagramWords = new List<IEnumerable<char>>();
for (int i = 0; i < numberOfWords; i++)
{
string wordForList = Console.ReadLine();
IEnumerable<char> wordCharacters = wordForList.ToLower().OrderBy(fl => fl);
anagramWords.Add(wordCharacters);
}
foreach (var word in anagramWords)
{
// Here we are asking to compare the full set of elements
// with each other and we find if they contain the same data.
if (word.SequenceEqual(mainWord))
{
Console.WriteLine("Yes");
}
else
{
Console.WriteLine("No");
}
}
}

Related

Count how many time each Char is in a txt file in C#

I have a school homework, where I need to count how many times each letter is in a txt file, I can't use a dictionary and can't use LinQ, I then need to put it in order alphabetically, and in order of iterations.
string = "hello world"
output =
D=1
E=1
H=1
L=3
O=2
R=1
W=1
L=3
O=2
D=1
E=1
H=1
R=1
W=1
What I have so far works just for the order alphabetically , not for the itterations.
public void testChar() {
string text = File.ReadAllText(# "C:\Ecole\Session 2\Prog\Bloc 4\test.txt")?.ToUpper();
text = Regex.Replace(text, # "[^a-zA-Z]", "");
List < char > listChar = new List < char > ();
foreach(char lettre in text) {
listChar.Add(lettre);
}
int countPosition = 0;
List < int > position = new List < int > ();
listOfChar.Add(listChar[0]);
listOfRepetitions.Add(1);
position.Add(countPosition);
int jumpFirstItteration = 0;
foreach(var item in listChar) {
if (jumpFirstItteration == 0) {
jumpFirstItteration++;
}
if (listOfChar.Contains(item)) {
int pos = listOfChar.IndexOf(item);
listOfRepetitions[pos] += 1;
} else if (!listOfChar.Contains(item)) {
listOfChar.Add(item);
listOfRepetitions.Add(1);
countPosition++;
position.Add(countPosition);
}
}
}
Please help :D
The canonical way of computing a concordance is to use an array of integers for counting the letters, the same size as the number of different letters in the text - in this case, just the normal uppercase alphabetic characters A-Z.
Then you iterate through the uppercased letters and if they are in range, increment the count corresponding to that letter.
To simplify this you can make two observations:
To convert a letter to an index, just subtract 'A' from the character code.
To convert an index to a letter, just add 'A' to the index and cast the result back to a char. (The cast is necessary because the result of adding an int to a char is an int, not a char.)
Once you've done that, you'll have all the counts for the characters in alphabetical order. However, you also need the letters in order of frequency of occurrence. To compute that, you can use an overload of Array.Sort() that takes two arrays: The first parameter is an array to sort, and the second parameter is an array to sort in the same way as the first array.
If you pass the array of counts as the first array, and an array of all the letters being counted in alphabetical order as the second array (i.e. the letters A..Z) then after sorting the second array will give you the letters in the correct order to display with the first array.
Putting all that together:
public void testChar()
{
string filename = #"C:\Ecole\Session 2\Prog\Bloc 4\test.txt";
string text = File.ReadAllText(filename).ToUpper();
int[] concordance = new int[26]; // 26 different letters of the alphabet to count.
foreach (char c in text)
{
int index = c - 'A'; // A..Z will convert to 0..25; other chars will be outside that range.
if (index >= 0 && index < 26)
++concordance[index];
}
// Display frequency in alphabetic order, omitting chars with 0 occurances.
for (int i = 0; i < concordance.Length; ++i)
{
if (concordance[i] > 0)
Console.WriteLine($"{(char)('A'+i)} = {concordance[i]}");
}
Console.WriteLine();
// For sorting by frequency we need another array of chars A..Z in alphabetical order.
char[] aToZ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
Array.Sort(concordance, aToZ);
// Display frequency in occurance order, omitting chars with 0 occurances.
for (int i = 0; i < concordance.Length; ++i)
{
if (concordance[i] > 0)
Console.WriteLine($"{aToZ[i]} = {concordance[i]}");
}
}
maybe add something like a sort function?
position.sort((a,b)=> if a < b return 1; if a > b return -1; return 0;)
This would be a normal sorting function based on their integer value, but since you are dealing with a list, it becomes a little more tedious.
position.sort((a,b)=> if a[i] < b[i] return 1; if a[i] > b[i] return -1; return 0;)
where i the index of integers to be compared
Forgive me, I come from java
Not necessarilly the most efficient, but works.
First, a simple letter class thant can compare its properies.
public class Letter
{
public char Symbole { get; set; }
public int Frequency { get; set; }
public int CompareLetter(object obj)
{
Letter other = obj as Letter;
if (other == null) return 1;
return this.Symbole.CompareTo(other.Symbole);
}
public int CompareFrequency(object obj)
{
Letter other = obj as Letter;
if (other == null) return 1;
return this.Frequency.CompareTo(other.Frequency);
}
}
Then a method to populate a List of Letter
public static List<Letter> ReturnLettersCount(string fileName)
{
string text;
List<Letter> letters = new List<Letter>();
using (StreamReader sr = new StreamReader(fileName))
{
text = sr.ReadToEnd().ToLower();
}
foreach (char c in text)
{
if (char.IsLetter(c))
{
Letter letter = letters.Find((letter) => letter.Symbole == c);
if (letter == null)
{
letters.Add(new Letter() { Symbole = c, Frequency = 1 });
}
else
{
letter.Frequency++;
}
}
}
return letters;
}
And a user code
static void Main(string[] args)
{
string fileName = #"path\to\your\textFile.txt";
List<Letter> letters = ReturnLettersCount(fileName);
letters.Sort( (a, b) => a.CompareLetter(b) );
foreach(Letter letter in letters)
{
Console.WriteLine($"{letter.Symbole}: {letter.Frequency}");
}
Console.WriteLine("--------------------------");
letters.Sort((b, a) => a.CompareFrequency(b));
foreach (Letter letter in letters)
{
Console.WriteLine($"{letter.Symbole}: {letter.Frequency}");
}
}
Without Linq and Dictionary it's like walking by foot to the grocery 20 miles away. ;)
//C# vs >= 8.0
using System;
using Entry = System.Collections.Generic.KeyValuePair<char, int>;
// class header ...
public static void Sort() {
var text = "hello world";
var contest = new System.Collections.Generic.List<Entry>(text.Length);
foreach (var c in text) {
if (!char.IsLetter(c)) {
continue;
}
var i = contest.FindIndex(kv => kv.Key == c);
if (i < 0) {
contest.Add(new(c, 1));
}
else {
contest[i] = new(c, contest[i].Value + 1);
}
}
contest.Sort((e1, e2) => e1.Key - e2.Key);
Console.Write("\n{0}\n\n", string.Join('\n', contest));
contest.Sort((e1, e2) => e2.Value - e1.Value);
Console.Write("\n{0}\n\n", string.Join('\n', contest));
}
A few suggestions that may come in handy.
You could build a container (the CharInfo class object here), to store the information you collect about each char found, it's position and how many times it's found in your text file.
This class container implements IComparable (the comparer just tests the char value, as an integer, against the char value of another object).
This makes it simple to sort a List<CharInfo>, just calling its Sort() method:
public class CharInfo : IComparable<CharInfo>
{
public CharInfo(char letter, int position) {
Character = letter;
Positions.Add(position);
}
public char Character { get; }
public int Occurrences { get; set; } = 1;
public List<int> Positions { get; } = new List<int>();
public static List<string> CharsFound { get; } = new List<string>();
public int CompareTo(CharInfo other) => this.Character - other.Character;
}
Since you can use the Regex class, you can then use Regex.Matches() to return all characters in the [a-zA-Z] range. Each Match object also stores the position where the character was found.
(As a note, you could just use the Matches collection and GroupBy() the results, but you cannot use LINQ and the other suggestions would just be mute :)
Looping the Matches collection, you test whether a char is already present in the list; if it is, add 1 to the Occurrences Property and add its position to the Positions Property.
If it's not already there, add a new CharInfo object to the collection. The constructor of the class takes a char and a position. The Occurrences Property defaults to 1 (you create a new CharInfo because you have found a new char, which is occurrence n° 1).
In the end, just Sort() the collection using its custom comparer. Sort() will call the IComparable.CompareTo() method of the class.
string text = File.ReadAllText([File Path]);
var matches = Regex.Matches(text, #"[a-zA-Z]", RegexOptions.Multiline);
var charsInfo = new List<CharInfo>();
foreach (Match m in matches) {
int pos = CharInfo.CharsFound.IndexOf(m.Value);
if (pos >= 0) {
charsInfo[pos].Occurrences += 1;
charsInfo[pos].Positions.Add(m.Index);
}
else {
CharInfo.CharsFound.Add(m.Value);
charsInfo.Add(new CharInfo(m.Value[0], m.Index));
}
}
// Sort the List<CharInfo> using the provided comparer
charsInfo.Sort();
Call CharInfo.CharsFound.Clear() before you search another text file.
You can then print the results as:
foreach (var chInfo in charsInfo) {
Console.WriteLine(
$"Char: {chInfo.Character} " +
$"Occurrences: {chInfo.Occurrences} " +
$"Positions: {string.Join(",", chInfo.Positions)}");
}
Note that upper and lower case chars are treated as distinct elements.
Modify as required.

Adding characters to an array list only if it does not already exist

The code below is supposed to read a text file and count all ASCII characters in the file and add up the frequency. Then, it has to write the character, ASCII value and frequency to an output file. The code is below:
class CharacterFrequency
{
char ch;
int frequency;
public char getCharacter()
{
return ch;
}
public void setCharacter(char ch)
{
this.ch = ch;
}
public int getfrequency()
{
return frequency;
}
public void setfrequency(int frequency)
{
this.frequency = frequency;
}
static void Main()
{
Console.WriteLine("Enter the file path");
var InputFileName = Console.ReadLine();
Console.WriteLine("Enter the outputfile name");
var OutputFileName = Console.ReadLine();
StreamWriter streamWriter = new StreamWriter(OutputFileName);
string data = File.ReadAllText(InputFileName);
ArrayList al = new ArrayList();
//create two for loops to traverse through the arraylist and compare
for (int i = 0; i < data.Length; i++)
{
int k = 0;
int f = 0;
for (int j = 0; j < data.Length; j++)
{
if (data[i].Equals(data[j]))
{
f++;
}
}
if (!al.Contains(data[i]))
{
al.Add(data[i] + "(" + (int)data[i] + ")" + f + " ");
}
else
{
k++;
}
//i added the below if statement but it did not fix the issue
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
}
streamWriter.Close();
}
}
The code compiles and runs perfectly fine, but the output file is not correct. It is adding letters that have already been reviewed. I've added an image with the output file showing the incorrect output it is creating. --> enter image description here
How do I check if a character already exists in the array list? The way I am using is not working properly and I have been working on this for a few weeks now to no success. I have tried using the debugger but this issue will not show up there as the code still runs and compiles correctly.
An ArrayList is not well suited for this task, and in fact ArrayLists are not really used anymore. If someone is telling you that you have to do this with an ArrayList
A dictionary would be a much better container for this data. You can use the character as the key, and the count as the value.
Here's one way to do this:
var inputPath = #"c:\temp\temp.txt";
var outputPath = #"c:\temp\results.txt";
var data = new Dictionary<char, int>();
// For each character in the file, add it to the dictionary
// or increment the count if it already exists
foreach (var character in File.ReadAllText(inputPath))
{
if (data.ContainsKey(character)) data[character]++;
else data.Add(character, 1);
}
// Create our results summary
var results = data.ToList()
.Select(item => $"{item.Key} ({(int) item.Key}) {item.Value}");
// Write results to output file
File.WriteAllLines(outputPath, results);
If you have to use an ArrayList (which no one ever uses anymore, but you say have you to for some reason), it would only be useful for storing the results but not keeping track of the counts.
One way to use an ArrayList would be in combination with the Linq extension methods Distinct and Count (first to find all distinct characters, and next to get the count of each one):
foreach (var chr in data.Distinct())
{
al.Add($"{chr} ({(int) chr}) {data.Count(c => c == chr)}");
}
Your algorithm works, but you are duplicating the output as you are writing to the file inside the loop, that is why you are seeing duplicates in the result. If you move the code outside the loop, it should be ok.
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
I would suggest that your algorithm while correct will behave poorly for performance, you are doing too many unnecessary comparisons, perhaps you should read/check more about using dictionaries to store the results.

Matching an entered String to a random String

I've been stuck on this for a while now and i cant seem to get it to work. I want my program to be able to select a random word from the "Words" array (array contents previously added by the user) and allow the user to then enter another word and see if it matches the randomly selected word selected by the program from the array. If the words match a message will be out put but if not a message will also be output but the system should indicate to the user if any letters that they had entered were in the random String. I know this is quite a bit but I've been stuck for ages haha, thanks!
Here is part of the code i have been using, a bit simplified.
private void btnGuess_Click(object sender, EventArgs e)
{
string guess = txtGuess.Text;
string[] words = new string[6];
lstWords.Items.Add(txtEnterWord.Text);
Random rand = new Random();
for (int i = 0; i < words.Length; i++)
{
words[i] = rand.ToString();
}
if (String.Equals(guess, rand))
{
MessageBox.Show("Congratulations you have won! Your words are a match");
}
else
{
MessageBox.Show("Sorry but your words are not a match, try again");
}
}
you have to
initialize your words array with actual words
have a method that picks up a random word from words array
like follows:
private void btnGuess_Click(object sender, EventArgs e)
{
string guess = txtGuess.Text;
string[] words = new string[6] { "word1", "word2", "word3", "word4", "word5", "word6" }; //<--| initialize words array
lstWords.Items.Add(txtEnterWord.Text); //<--| what is that for?
string randWord = GetRandomWord(words); //<--| get rabdom word from words array
if (String.Equals(guess, randWord))
{
MessageBox.Show("Congratulations you have won! Your words are a match");
}
else
{
MessageBox.Show("Sorry but your words are not a match, try again");
}
}
static private string GetRandomWord(string[] words)
{
Random rnd = new Random();
return words[rnd.Next(0, words.Length)].ToString();
}
Random rand = new Random()
for (int i = 0; i < words.Length; i++)
{
words[i] = rand.ToString();
}
In this loop you're assigning the output of rand.ToString() to every element in your array. If you looked at the array after the loop every element would then be "System.Random" because calling the ToString method on an object of type Random returns the type of the object, as a string.
When you create a new Random object you're creating an object. An object that can return you random numbers. You're NOT creating a random number.
You're wanting to pick one of the strings out of the array, this is how you can get it out.
string thirdWordFromMyArrayOfWords = words[3];
To get a random number using Random that will be within the range of your words element:
int randomNumberWithinTheRangeOfMyArray = rand.Next(0,words.Length-1)
You need to subtract one because the array has 6 elements (words.Length = 6) but it starts counting at zero 0,1,2,3,4,5 so if you tried to reference words[6] you'll throw an exception.
int randomNumberWithinTheRangeOfMyArray = rand.Next(0,words.Length-1);
string randomWordFromArray = words[randomNumberWithinTheRangeOfMyArray];
if (String.Equals(guess, randomWordFromArray))
and it can be further condensed
if (String.Equals(guess, words[rand.Next(0,words.Length-1)]))
Something else to consider is that since your calling for a new random number every time the button is clicked you'll get a new random number and therefore a new random word out of the array.
using System;
using System.Collections.Generic;
using System.Linq;
namespace RandomWords
{
class Program
{
static void Main(string[] args)
{
string[] words = new[] { "csharp", "Stack", "overflow", "microsoft", "word5", "Coding"};
Random rnum = new Random();
string input = null;
while ( input != "end") {
int intnum = rnum.Next(0, words.Length);
Console.WriteLine("Guess a word or enter end to exit");
input = Console.ReadLine();
List<string> l = words.Where(x => x == input).ToList<string>();
if (l.Count != 0) { Console.WriteLine("Congratulations you have won! Your words are a match"); } else { Console.WriteLine("Sorry but your words are not a match, try again"); }
}
}
}
}

Iterating backwards through an char array after finding a known word

I've got a project I'm working on in C#. I've got two char array's. One is a sentence and one is a word. I've got to iterate through the sentence array until I find a word that matches the word that was turned into an word array what I'm wondering is once I find the word how do I iterate backwards through the sentence array at the point I found the word back through the same length as the word array?
Code :
String wordString = "(Four)";
String sentenceString = "Maybe the fowl of Uruguay repeaters (Four) will be found";
char[] wordArray = wordString.ToCharArray();
List<String> words = sentenceString.Split(' ').ToList<string>();
//This would be the part where I iterate through sentence
foreach (string sentence in sentArray)
{
//Here I would need to find where the string of (Four) and trim it and see if it equals the wordString.
if (sentence.Contains(wordString)
{
//At this point I would need to go back the length of wordString which happens to be four places but I'm not sure how to do this. And for each word I go back in the sentence I need to capture that in another string array.
}
I don't know if I'm being clear enough on this but if I'm not please feel free to ask.. Thank you in advanced. Also what this should return is "fowl of Uruguay repeaters". So basically the use case is for the number of letters in the parenthesis the logic should return the same number of words before the word in parenthesis.
our are you. I have few question concerned to this exercise.
If the Word (four) was in beginning it should not return? or return all string?
As the length of four is equal to 4 imagine if that word appear as the second word on sentence what it should return just the first word or return 4 words even including the (four) word.?
My solution is the laziest one I just see your question and decide to help.
My solution assumes it return all the word before the (four) if the length is bigger than the word before the (four) word.
My solution return empty string if the word (four) is in the beginning.
My solution return Length of (four) (4) words before (four) word.
ONCE AGAIN IT IS NOT MY BEST APPROACH.
I see the code bellow:
string wordString = "(Four)";
string sentenceString = "Maybe the fowl of Uruguay repeaters (Four) will be found";
//Additionally you can add splitoption to remove the empty word on split function bellow
//Just in case there are more space in sentence.
string[] splitedword = sentenceString.Split(' ');
int tempBackposition = 0;
int finalposition = 0;
for (int i = 0; i < splitedword.Length; i++)
{
if (splitedword[i].Contains(wordString))
{
finalposition = i;
break;
}
}
tempBackposition = finalposition - wordString.Replace("(","").Replace(")","").Length;
string output = "";
tempBackposition= tempBackposition<0?0:tempBackposition;
for (int i = tempBackposition; i < finalposition; i++)
{
output += splitedword[i] + " ";
}
Console.WriteLine(output);
Console.ReadLine();
If it's not what you want can you answer my questions on top? or help me to understand were it's wrong
int i ;
string outputString = (i=sentenceString.IndexOf(wordString))<0 ?
sentenceString : sentenceString.Substring(0,i) ;
var wordString = "(Four)";
int wordStringInt = 4; // Just do switch case to convert your string to int
var sentenceString = "Maybe the fowl of Uruguay repeaters (Four) will be found";
var sentenceStringArray = sentenceString.Split(' ').ToList();
int wordStringIndexInArray = sentenceStringArray.IndexOf(wordString) - 1;
var stringOutPut = "";
if (wordStringIndexInArray > 0 && wordStringIndexInArray > wordStringInt)
{
stringOutPut = "";
while (wordStringInt > 0)
{
stringOutPut = sentenceStringArray[wordStringInt] + " " + stringOutPut;
wordStringInt--;
}
}
What you are matching is kind of complex, so for a more general solution you could use regular expressions.
First we declare what we are searching for:
string word = "(Four)";
string sentence = "Maybe the fowl of Uruguay repeaters (Four) will be found";
We will then search for the words in this string using regular expressions. Since we don't want to match whitespace, and we need to know where each match actually starts and we need to know the word inside the parenthesis we tell it that we optionally want opening and ending parenthesis, but we also want the contents of those as a match:
var words = Regex.Matches(sentence, #"[\p{Ps}]*(?<Content>[\w]+)[\p{Pe}]*").Cast<Match>().ToList();
[\p{Ps}] means we want opening punctuation ([{ etc. while the * indicates zero or more.
Followed is a sub-capture called Content (specified by ?<Content>) with one or more word characters.
At the end we specify that we want zero or more ending punctuation.
We then need to find the word in the list of matches:
var item = words.Single(x => x.Value == word);
Then we need to find this item's index:
int index = words.IndexOf(item);
At this point we just need to know the length of the contents:
var length = item.Groups["Content"].Length;
This length we use to go back in the string 4 words
var start = words.Skip(index - length).First();
And now we have everything we need:
var result = sentence.Substring(start.Index, item.Index - start.Index);
Result should contain fowl of Uruguay repeaters.
edit: It may be a lot simpler to just figure out the count from the word rather than from the content. In that case the complete code should be the following:
string word = "(Four)";
string sentence = "Maybe the fowl of Uruguay repeaters (Four) will be found";
var wordMatch = Regex.Match(word, #"[\p{Ps}]*(?<Content>[\w]+)[\p{Pe}]*");
var length = wordMatch.Groups["Content"].Length;
var words = Regex.Matches(sentence, #"\S+").Cast<Match>().ToList();
var item = words.Single(x => x.Value == word);
int index = words.IndexOf(item);
var start = words.Skip(index - length).First();
var result = sentence.Substring(start.Index, item.Index - start.Index);
\S+ in this case means "match one or more non-whitespace character".
You should try something like the following, which uses Array.Copy after it finds the number word. You will still have to implement the ConvertToNum function correctly (it is hardcoded in for now), but this should be a quick and easy solution.
string[] GetWords()
{
string sentenceString = "Maybe the fowl of Uruguay repeaters (Four) will be found";
string[] words = sentenceString.Split();
int num = 0;
int i; // scope of i should remain outside the for loop
for (i = 0; i < words.Length; i++)
{
string word = words[i];
if (word.StartsWith("(") && word.EndsWith(")"))
{
num = ConvertToNum(word.Substring(1, word.Length - 1));
// converted the number word we found, so we break
break;
}
}
if (num == 0)
{
// no number word was found in the string - return empty array
return new string[0];
}
// do some extra checking if number word exceeds number of previous words
int startIndex = i - num;
// if it does - just start from index 0
startIndex = startIndex < 0 ? 0 : startIndex;
int length = i - startIndex;
string[] output = new string[length];
Array.Copy(words, startIndex, output, 0, length);
return output;
}
// Convert the number word to an integer
int ConvertToNum(string numberStr)
{
return 4; // you should implement this method correctly
}
See - Convert words (string) to Int, for help implementing the ConvertToNum solution. Obviously it could be simplified depending on the range of numbers you expect to deal with.
Here is my solution, im not using regex at all, for the sake of easy understanding:
static void Main() {
var wordString = "(Four)";
int wordStringLength = wordString.Replace("(","").Replace(")","").Length;
//4, because i'm assuming '(' and ')' doesn't count.
var sentenceString = "Maybe the fowl of Uruguay repeaters (Four) will be found";
//Transform into a list of words, ToList() to future use of IndexOf Method
var sentenceStringWords = sentenceString.Split(' ').ToList();
//Find the index of the word in the list of words
int wordIndex = sentenceStringWords.IndexOf(wordString);
//Get a subrange from the original list of words, going back x Times the legnth of word (in this case 4),
var wordsToConcat = sentenceStringWords.GetRange(wordIndex-wordStringLength, wordStringLength);
//Finally concat the output;
var outPut = string.Join(" ", wordsToConcat);
//Output: fowl of Uruguay repeaters
}
I have a solution for you:
string wordToMatch = "(Four)";
string sentence = "Maybe the fowl of Uruguay repeaters (Four) will be found";
if (sentence.Contains(wordToMatch))
{
int length = wordToMatch.Trim(new[] { '(', ')' }).Length;
int indexOfMatchedWord = sentence.IndexOf(wordToMatch);
string subString1 = sentence.Substring(0, indexOfMatchedWord);
string[] words = subString1.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var reversed = words.Reverse().Take(length);
string result = string.Join(" ", reversed.Reverse());
Console.WriteLine(result);
Console.ReadLine();
}
Likely this can be improved regardng performance, but I have a feeling you don't care about that. Make sure you are using 'System.Linq'
I assumed empty returns when input is incomplete, feel free to correct me on that. Wasn't 100% clear in your post how this should be handled.
private string getPartialSentence(string sentence, string word)
{
if (string.IsNullOrEmpty(sentence) || string.IsNullOrEmpty(word))
return string.Empty;
int locationInSentence = sentence.IndexOf(word, StringComparison.Ordinal);
if (locationInSentence == -1)
return string.Empty;
string partialSentence = sentence.Substring(0, locationInSentence);
string[] words = partialSentence.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
int nbWordsRequired = word.Replace("(", "").Replace(")", "").Length;
if (words.Count() >= nbWordsRequired)
return String.Join(" ", words.Skip(words.Count() - nbWordsRequired));
return String.Join(" ", words);
}
I went with using an enumeration and associated dictionary to pair the "(Four)" type strings with their integer values. You could just as easily (and maybe easier) go with a switch statement using
case "(Four)": { currentNumber = 4; };
I feel like the enum allows a little more flexibility though.
public enum NumberVerb
{
one = 1,
two = 2,
three = 3,
four = 4,
five = 5,
six = 6,
seven = 7,
eight = 8,
nine = 9,
ten = 10,
};
public static Dictionary<string, NumberVerb> m_Dictionary
{
get
{
Dictionary<string, NumberVerb> temp = new Dictionary<string, NumberVerb>();
temp.Add("(one)", NumberVerb.one);
temp.Add("(two)", NumberVerb.two);
temp.Add("(three)", NumberVerb.three);
temp.Add("(four)", NumberVerb.four);
temp.Add("(five)", NumberVerb.five);
temp.Add("(six)", NumberVerb.six);
temp.Add("(seven)", NumberVerb.seven);
temp.Add("(eight)", NumberVerb.eight);
temp.Add("(nine)", NumberVerb.nine);
temp.Add("(ten)", NumberVerb.ten);
return temp;
}
}
static void Main(string[] args)
{
string resultPhrase = "";
// Get the sentance that will be searched.
Console.WriteLine("Please enter the starting sentance:");
Console.WriteLine("(don't forget your keyword: ie '(Four)')");
string sentance = Console.ReadLine();
// Get the search word.
Console.WriteLine("Please enter the search keyword:");
string keyword = Console.ReadLine();
// Set the associated number of words to backwards-iterate.
int currentNumber = -1;
try
{
currentNumber = (int)m_Dictionary[keyword.ToLower()];
}
catch(KeyNotFoundException ex)
{
Console.WriteLine("The provided keyword was not found in the dictionary.");
}
// Search the sentance string for the keyword, and get the starting index.
Console.WriteLine("Searching for phrase...");
string[] words = sentance.Split(' ');
int searchResultIndex = -1;
for (int i = 0; (searchResultIndex == -1 && i < words.Length); i++)
{
if (words[i].Equals(keyword))
{
searchResultIndex = i;
}
}
// Handle the search results.
if (searchResultIndex == -1)
{
resultPhrase = "The keyword was not found.";
}
else if (searchResultIndex < currentNumber)
{
// Check the array boundaries with the given indexes.
resultPhrase = "Error: Out of bounds!";
}
else
{
// Get the preceding words.
for (int i = 0; i < currentNumber; i++)
{
resultPhrase = string.Format(" {0}{1}", words[searchResultIndex - 1 - i], resultPhrase);
}
}
// Display the preceding words.
Console.WriteLine(resultPhrase.Trim());
// Exit.
Console.ReadLine();
}

C# - Looping through pairs and matching

So I'm stuck on a program where I have a series of pairs that may or may not be able to connect together to form a complete path through the pairs. I need to be able to check if the second item in a pair can match the first item in another pair and so on until there are no pairs left. For example, my pairs might be:
(1,5)
(2,4)
(3,2)
(5,3)
(4,3)
I would need to be able to somehow iterate through the pairs and check if I can get a complete path that travels through each one, based on if the second digit of a pair matches the first digit of the next pair. In this example, the output would be: (1,5), (5,3), (3,2), (2,4), (4,3) forming a complete match. If a match can't be formed, I need to report a failure. The input is based on a text file. So far I've been able to read the file with a Streamreader and split the pairs based on newline, then iterate through and split each pair into its items based on the comma. I'm pretty much clueless on how to proceed, if anyone has some ideas I would appreciate it.
StreamReader sr = new StreamReader("inputs.txt");
string line = null;
line = sr.ReadToEnd();
var str = line.Trim().Split('\n');
int length = str.Length;
int index=1;
while (index < length)
{
var pair = str[index].Split(',');
var item1 = pair[0];
var item2 = pair[1];
}
The problem you described can be converted to another form; a graph.
Here's what it looks like for the example you gave.
I drew an arrow from 1 to 5 since there was the pair (1,5), etc.
A path on a graph like this can only go the directions of the arrows.
What you want to know is: "is there a path in this graph that uses every pair, i.e. goes over every edge?"
Such a path is known as an Eulerian Directed Path
Wikipedia lists two algorithms for finding such paths, Fleury's and Hierholzer's, both of which were discovered in the late 1800's. Hopefully, this gives you an idea of where to start in solving this problem.
First, you need to strip the parenthesis - if they are present in your input file. See string.Trim method for that.
The brute force approach:
public class Pair
{
public string First;
public string Second;
}
List<Pair> pairs = new List<Pair>();
for (int index = 0; iter < str.Length; index++)
{
var pair = str[index].Split(',');
pairs.Add(new Pair(){First = pair[0], Second = pair[1]});
}
List<Pair> ordered = new List<Pair>();
ordered.Add(pairs[0]);
pairs.RemoveAt(0);
while (pairs.Count > 0)
{
bool found = false;
for (int iter = 0; iter < pairs.Count; iter++)
{
if (ordered[ordered.Count - 1].Second == pairs[iter].First)
{
ordered.Add(pairs[iter]);
pairs.RemoveAt(iter);
found = true;
break;
}
}
if (!found)
{
<report error>
break;
}
}
Error checking is left as an exercise for the reader.
WARNING: This is not tested!!
using System;
using System.IO;
class t1{
public static void Main(String[] args)
{
StreamReader sr = new StreamReader("inputs.txt");
string line = null;
line = sr.ReadToEnd();
var str = line.Trim().Split('\n');
int length = str.Length;
int[][] arr=new int[10][];//[str.Length][2];
int index=0;
while (index < length)
{
var pair = str[index].Split(',');
var item1 = Convert.ToInt32(pair[0]);
var item2 = Convert.ToInt32(pair[1]);
arr[index]=new int[]{item1,item2};
index++;
}
for (int i=0;i<arr.Length;i++)
{
for (int j=i+1;j<arr.Length;j++)
{
if (arr[i][1] == arr[j][0])
{
//MATCH
}
else
{
//FAILURE
}
}
}
}
}

Categories