I hope you're all doing well. I'll try to keep myself short so let me give you an example right away.
Let's say that I have two lists. In the first list there are different words on different lines. In the second list there are synonyms for each and every word.
List 1:
hello
exhausted
happy
List 2:
hi, hey, howdy
beat, foreworn
glad
The console application outputs a random line number's string from the first list and then it let's me enter a synonym. After this, the console app checks if the synonym that I stated is within the same line number but in list 2.
I would like to count how many letters there are before, in between and after the commas.
Can anyone help? I'm far from a professional when it comes to C# so if anyone thinks I should rewrite the lists in any different way to make it easier I would be happy to do so.
Thanks!
Edit: The reason I want to do this is because if the console outputs "hello" for example, all it takes for the player is to enter "h" and it counts as correct. This is because there is an H in "hi" (see list 2). If I knew how many letters there are between the commas then the console would be able to give the player a wrong if the input's characters is more or less than the number of characters in list 2.
Split your string..
using System.Collections.Generic;
using System.Linq;
// ....
bool CheckSynonym(List<string> list1,List<string> list2, string provided, string synonymprovided)
{
if (list1.IndexOf(provided)<0) return false;
if (list1.IndexOf(provided)>=list2.Count) return false;
string s = list2[list1.IndexOf(provided)];
List<string> lstwords = s.Split( new char[] { ',' } ).ToList();
if (lstwords.IndexOf(" "+synonymprovided) >= 0) return true;
if (lstwords.IndexOf(synonymprovided) >= 0) return true;
return false;
}
This could work fine.. but I'd like to make a remark about the way you store your data. You stated "After this, the console app checks if the synonym that I stated is within the same line number but in list 2."
When you are going to expand your synonym dictionary, this is not handy, because you will have to check line numbers. I would use a single list, to include the words in the first list, like so
List:
hello, hi, hey, howdy
exhausted, beat, foreworn
happy, glad
Code can be straightforward, like
using System.Collections.Generic;
using System.Linq;
// ....
bool CheckSynonym(List<string> list, string provided, string synonymprovided)
{
foreach (string s in list)
{
List<string> lstwords = s.Split( new char[] { ',' } ).ToList();
if (lstwords.IndexOf(provided ) == 0)
if (lstwords.IndexOf(synonymprovided) > 0) return true;
else if (lstwords.IndexOf(" " + synonymprovided) >= 0) return true;
}
return false;
}
Note: this second solution allows for a single list.. but it will be slower !
One possible method:
string x1 = "hi, hey, howdy";
x1.Split(',').ToList().ForEach(x => Console.WriteLine(x.Trim().ToCharArray().Count()));
Prints
2,
3,
5
Related
What I'm trying to do is to create a function that will rearrange a string of numbers like "1234" to "4321". I'm certain that there are many much more efficient ways to do this than my method but I just want to see what went wrong with what I did because I'm a beginner at programming and can use the knowledge to get better.
My thought process for the code was to:
find the largest number in the inputted string
add the largest number into a list
remove the largest number from the inputted string
find the largest number again from the (now shorter) string
So I made a function that found the largest number in a string and it worked fine:
static int LargestNumber(string num)
{
int largestnumber = 0;
char[] numbers = num.ToCharArray();
foreach (var number in numbers)
{
int prevNumber = (int) char.GetNumericValue(number);
if (prevNumber >= largestnumber)
{
largestnumber = prevNumber;
}
}
return largestnumber;
}
Now the rearranging function is what I am having problems with:
static List<int> Rearrange(string num)
{
List<int> rearranged = new List<int>(); // to store rearranged numbers
foreach (var number in num) //for every number in the number string
{
string prevnumber = number.ToString(); // the previous number in the loop
if (prevnumber == LargestNumber(num).ToString()) // if the previous number is the larges number in the inputted string (num)
{
rearranged.Add(Convert.ToInt32(prevnumber)); // put the previous number into the list
// removing the previous number (largest) from the inputted string and update the inputted string (which should be now smaller)
StringBuilder sb = new StringBuilder(num);
sb.Remove(num.IndexOf(number), 1);
num = sb.ToString();
}
}
return rearranged; // return the final rearranged list of numbers
}
When I run this code (fixed for concatenation):
var rearranged = Rearrange("3250");
string concat = String.Join(" ", rearranged.ToArray());
Console.WriteLine(concat);
All I get is:
5
I'm not sure what I'm missing or what I'm doing wrong - the code doesn't seem to be going back after removing '5' which i s the highest number then removing the next highest number/
Your issue is your if statement within your loop.
if (prevnumber == LargestNumber(num).ToString()
{
rearranged.Add(Convert.ToInt32(prevnumber));
//...
}
You only ever add to your List rearranged if the value of prevnumber is the largest value, which is false for every number but 5, so the only value that ever gets added to the list is 5.
That's the answer to why it's only returning 5, but I don't think that will make your method work properly necessarily. You're doing a very dangerous thing by changing the value of the collection you are iterating over (the characters in num) from within the loop itself. Other answers have been written for you containing a method that rearranges the numbers as you've described.
Your Rearrange method is returning List<int> when you try to write that to the console, the best it can do is write System.Collections.Generic.List1[System.Int32] (its type)
Instead of trying to write the list, convert it first into a data type that can be written (string for example)
eg:
var myList = Rearrange("3250");
string concat = String.Join(" ", myList.ToArray());
Console.WriteLine(concat);
Building on pats comment you could iterate through your list and write them to the console.
e.g.
foreach(var i in Rearrange(3250))
{
console.writeline(i.ToString());
}
or if you want to see the linq example.
using system.linq;
Rearrange(3250).foreach(i => console.writeline(i.ToString()));
--edit after seeing you're only getting '5' output
This is because your function only adds number to the list if they are the largest number in your list, which is why 5 is only being added and returned.
Your Rearrange method can be written easily using Array.Sort (or similar with (List<T>) :
int[] Rearrange(int num)
{
var arr = num.ToString ().ToCharArray ();
Array.Sort (arr, (d1, d2) => d2 - d1);
return Array.ConvertAll (arr, ch => ch - '0');
}
Just reading your first sentence
Does not test for integers
static int ReversedNumber(string num)
{
char[] numbers = num.ToCharArray();
Array.Sort(numbers);
Array.Reverse(numbers);
Debug.WriteLine(String.Concat(numbers));
return (int.Parse(String.Concat(numbers)));
}
Because your foreach loop within Rearrange method only loop through the original num. The algorithm doesn't continue to go through the new num string after you have removed the largest number.
You can find the problem by debugging, this foreach loop in Rearrange goes only 4 times if your input string is "3250".
I have a text file which contains a list of about 150000 words. I loaded the the words into a dictionary and word lookup works fine for me. Now i want to search the dictionary to see if the dictionary contains a word starting from a particular alphabet.
I am using
foreach(KeyValuePair pair in dict ){
}
for this purpose. This seems to work fine for smaller word lists. But it doesnt work for 150000 wordlist. Could anyone help please.
void WordAvailable (char sLetter)
{
notAvail = true;
int count = 0;
do {
foreach (KeyValuePair<string,string> pair in dict) {
randWord = pair.Value;
count++;
if (randWord [0] == sLetter && !ListTest.usedWordsList.Contains (randWord)) {
notAvail = false;
startingLetter = char.ToString (sLetter);
break;
}
if (count >= dict.Count) {
ChooseRandomAlpha ();
sLetter = alpha;
count = 0;
}
}
} while(notAvail);
}
Now I want to search the dictionary to see if the dictionary contains a word starting from a particular alphabet.
That sounds like you want a SortedSet rather than a Dictionary. You can use GetViewBetween to find all the entries in the set that lie between two bounds. The lower bound would probably be "the string you're starting with" and for the upper bound, you could either work out "the last possible string starting with those characters" or use an exclusive upper bound by manually ignoring anything that doesn't start with your prefix, and "incrementing" the last character of your prefix. So for example, to find all words beginning with "tim" you can use GetViewBetween("tim", "tin") and ignore tin if it's in the dictionary.
Note that ordering can be an "interesting" exercise when it comes to multiple cultures etc. If this is just an academic exercise and you'll only have ASCII characters, you might want to lower case each word as you add it to the set, and then use an ordinal comparison. If you do need a culture-sensitive ordering, you could make that case-insensitive easily... but working out the upper bound for the prefix will be trickier.
Example of using GetViewBetween:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
var words = new SortedSet<string>(StringComparer.Ordinal)
{
"cat", "dog", "banana", "laptop", "mug",
"coffee", "microphone", "water", "stairs", "phone"
};
foreach (var word in words.GetViewBetween("d", "n"))
{
Console.WriteLine(word);
}
}
}
Output:
dog
laptop
microphone
mug
An alternative would be to build your own trie implementation (or find an existing one) but I don't know of one in the BCL.
So I'm using this code down here to figure out all the words that could be spelled out of the alphabet variable, the problem is , I build this alphabet variable each time I call this based on the board of random letters in front of the user. What i see though , and of course, is "aaab" for example...
What I'm after is for code to only use the letter as many times as it appears in the alphabet var, so that it can't do something like "aaab" but just "ab"
I understand this code that I found in another thread is made to build combinations of the letters into 4 letter words, or arrangements,
I'm wondering if theres a simple way using SelectMany or Select, to not add up its self if its already been used, keep in mind there could be multiple "a's" in the alphabet var to begin with, so if theres 2 A's in there, it should still be able to to AAB, just not AAAB. I am a newbie, I know that I could go through my own list and add letters together based on how many times they actually exist in the alphabet string..im just wondering if theres a way to interupt i or x and not add to q if its already been used...
sorry if this is confusing... thank you :)
// I found this in another thread and seemed to work great and fast.
var alphabet = "abcd";
var q = alphabet.Select(x => x.ToString());
int size = 4;
for (int i = 0; i < size - 1; i++)
q = q.SelectMany(x => alphabet, (x, y) => x + y);
foreach (var item in q)
( DO STUFF)
To reach your goal, you must find a way to mark letters in your alphabet which are already used and avoid using these letters a second time.
To do so you need a data structure which can store more than the letters alone, so a list of letters (or a string) is not sufficient.
Try to bulid a list of classes like this one:
class UsedLetter
{
char letter;
bool used;
}
Then you can mark each letter as used after you drew it from the list.
Improvement
You may also store your alphabet as a list of characters:
List<char> alphabet;
and remove each letter from the alphabet after its drawn.
Here's how I have achieved what I think you're after:
using System;
using System.Collections.Generic;
using System.Linq;
namespace WordPerms
{
class Program
{
Stack<char> chars = new Stack<char>();
List<string> words = new List<string>();
static void Main(string[] args)
{
Program p = new Program();
p.GetChar("abad");
foreach (string word in p.words)
{
Console.WriteLine(word);
}
}
// This is called recursively to build the list of words.
private void GetChar(string alpha)
{
string beta;
for (int i = 0; i < alpha.Length; i++)
{
chars.Push(alpha[i]);
beta = alpha.Remove(i, 1);
GetChar(beta);
}
char[] charArray = chars.Reverse().ToArray();
words.Add(new string(charArray));
if (chars.Count() >= 1)
{
chars.Pop();
}
}
}
}
Hope that helps, Greg.
I have been given the task of deserializing some data. The data has all been munged into a string which is in the following format:
InternalNameA8ValueDisplay NameA¬InternalNameB8ValueDisplay NameB¬ etc etc.
(ie, it has an internal name, '8', the value, the display name, followed by '¬' **). for example, you'd have FirstName8JoeFirst Name¬
I have no control over how this data is serialized, its legacy stuff.
I've thought of doing a bunch of splits on the string, or breaking it up into a char array and splitting down the text that way. But this just seems horrible. This way there is too much that could go wrong (e.g, if the value of a phone number (for example), could begin with '8'.
What I want to know is what peoples' approaches to this would be? Is there anything more clever i can do to break the data down
note: '¬' isn't actually the character, it looks more like an arrow pointing left. but I'm away from my machine at the moment. Doh!
Thanks.
Instead of using splits, I would recommend using a simple state machine. Walk over each characters until you hit a delimiter, then you know you're on the next field. That takes care of issues like an "8" in a phone number.
NOTE - untested code ahead.
var fieldValues = new string[3];
var currentField = 0;
var line = "InternalNameA8ValueDisplay NameA¬InternalNameB8ValueDisplay NameB¬";
foreach (var c in line)
{
if (c == '8' && currentField == 0)
{
currentField++; continue;
}
if (c == '¬')
{
currentField++; continue;
}
fieldValues[currentField] += c;
}
Dealing with wonky formats - always a good time!
Good luck,
Erick
It quite hard question to ask but I will try.
I have my 4 letters m u g o . I have also free string word(s).
Let'say: og ogg muogss. I am looking for any wise method to check if I can construct word(s) using only my letters. Please take notice that we used once g we won't be able to use it again.
og - possible because we need only **g** and **o**
ogg - not possible we took **o** and **g**, need the second **g**
muogss - not possible we took all, need also additional **s**
So my tactic is take my letters to char array and remove one by one and check how many left to build the word(s). But is it possible to use somehow in few lines, i do not know - regex ?
your method is only a few lines...
public static bool CanBeMadeFrom(string word, string letters)
{
foreach (var i in word.Select(c => letters.IndexOf(c, 0)))
{
if (i == -1) return false;
letters = letters.Remove(i, 1);
}
return true;
}
Here's a simple approach:
For your source word, create an array of size 26 and use it to count the how many times each letter appears.
Do the same for each word in your dictionary.
Then compare the two.
If every letter occurs less than or equal to as many times in the dictionary word as the source word, then it can be used to make that word. If not, then it cannot.
C-Sharpish Pseudocode: (probably doesn't compile as written)
/** Converts characters to a 0 to 25 code representing alphabet position.
This is specific to the English language and would need to be modified if used
for other languages. */
int charToLetter(char c) {
return Char.ToUpper(c)-'A';
}
/** Given a source word and an array of other words to check, returns all
words from the array which can be made from the letters of the source word. */
ArrayList<string> checkSubWords(string source, string[] dictionary) {
ArrayList<string> output = new ArrayList<string>();
// Stores how many of each letter are in the source word.
int[] sourcecount = new int[26]; // Should initialize to 0, automatically
foreach (char c in source) {
sourcecount[c]++;
}
foreach (string s in dictionary) {
// Stores how many of each letter are in the dictionary word.
int[] dictcount = new int[26]; // Should initialize to 0, automatically
foreach (char c in s) {
dictcount[c]++;
}
// Then we check that there exist no letters which appear more in the
// dictionary word than the source word.
boolean isSubword = true;
for (int i=0;i<26;i++) {
if (dictcount[i] > sourcecount[i]) {
isSubword = false;
}
}
// If they're all less than or equal to, then we add it to the output.
if (isSubWord) {
output.add(s);
}
}
return output;
}
If your definition of words is any arbitrary permutation of the available charactters then why do you need a regex? Just make sure you use each characters once. Regex doesn't know what a "correct word" is, and it's better to avoid using invalid characters by your algorithms than using them AND using a regex to make sure you didn't use them.