how to have a list of 'a' to 'z'? [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I have a code that I want to count the number of appearing each letter in alphabet in the input string.
I used a dictionary<char, int> to have a key for each letter and a value as the count of appearance.
So, how to have a list of 'a' to 'z' to use as keys?
I've tried this:
Dictionary<char, int> alphabetCounter = new Dictionary<char, int>();
for (char ch = 'a'; ch <= 'z'; ch++)
alphabetCounter[ch] = 0;
Is it a better way to have the list of 'a' to 'z'?
Thank you.

Using Linq try this to have a list from "a" to "z".
var list = Enumerable.Range('a', 'z' - 'a' + 1).Select(c => (char)c).ToList();
If you want to get in upper case, is the same but using upper case.
var list = Enumerable.Range('A', 'Z' - 'A' + 1).Select(c => (char)c).ToList();
Edit:
Your question is to get the list, but to get as dictionary you can use .ToDictionary() and initialize with value 0:
var dictionary = Enumerable.Range('a', 'z' - 'a' + 1).Select(c => (char)c).ToDictionary(i => (char)i, i => 0);
The same case to upper/lower case.

Here's a way to do it in LINQ:
var alphabetCounter = Enumerable.Range(97, 26).ToDictionary(i => (char)i, i => 0);
This will create a dictionary with all chars with values 0.
ASCII codes of alphabet (lowercase) begins at 97, we can then take 26 numbers from there and convert them to char.

Is performance a thing? You can keep it simple.
You do not need to create your own dictionary, register every possibility then start counter[i]++ for each ocurrence, seems a bit of an overkill to me.
You can group up the letters by using .GroupBy (System.Linq), then after you can check the count of each ocurrence.
Example:
var word = "test";
var groupedLetters = word.GroupBy(x => x);
foreach(var letter in groupedLetters)
{
Console.WriteLine($"{letter.Key} - {letter.Count()}");
}
Output:
t - 2
e - 1
s - 1

Hi May this example will help :
List<char> LS = new List<char>() {'A', 'B', 'C', 'D', 'A', 'D', 'B', 'A'};
Dictionary<char,int> AlphaDictionary = (from x in LS group x by x).Select(x => new {Alpha = x.Key, Count = x.Count()}).ToDictionary(x=>x.Alpha,x=>x.Count);

Related

I need to check if CHAR from Array1 contains some CHAR from my Array2 but I cant use Contains for CHAR... How to solve it? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I need to convert one phone number (badly written) to correct format. Example: + 420 741-854()642. to +420741854642
enter image description here
I think I'd just Regex replace all non digits with nothing;
var messy = "+ 420 741-854()642";
var clean = Regex.Replace(messy, "[^+0-9]", "");
For the regex pattern [^+0-9] this means "a single character that is from, the set of: (all characters except) + or 0 to 9 so in practice this pattern matches the space , hyphen -, parentheses () etc.. And any matched character (i.e. a bad character) is replaced with nothing
If you want to do it in the style you showed in the image then you can fix it by doing this:
string number = "+ 420 741-854()642.";
char[] povolene = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+' };
for(int i = 0; i < number.Length; i++) {
if (povolene.Contains(number[i])) {
.
.
.
}
}
This is a job for RegEx (Regular Expressions) :) you could have something like this: /+?\d+/gm which will return three matches from +420741-854()642 as ['+420741', '854', '642'] which can of course then be concatenated. You could always as well replace the '+' with '00' beforehand and just concatenate matches from /\d+/gm. This just matches all digits in the string.
https://regex101.com/ is a great resource for learning RegEx.
Technically, you can filter out digits (c >= '0' && c <= '9') with a help of Linq:
using System.Linq;
...
string source = "+ 420 741-854()642.";
string result = "+" + string.Concat(source.Where(c => c >= '0' && c <= '9'));

Find in the List of words with letters in certain positions

I'm doing a crossword puzzle maker. The user selects cells for words, and the program compiles a crossword puzzle from the dictionary (all words which can be used in the crossword) - List<string>.
I need to find a word (words) in a dictionary which matches given mask (pattern).
For example, I need to find all words which match
#a###g
pattern, i.e. all words of length 6 in the dictionary with "a" at index 1 and "g" at index 5
The number of letters and their position are unknown in advance
How do I realize this?
You can convert word description (mask)
#a###g
into corresponding regular expression pattern:
^\p{L}a\p{L}{3}g$
Pattern explained:
^ - anchor, word beginning
\p{L} - arbitrary letter
a - letter 'a'
\p{L}{3} - exactly 3 arbitrary letters
g - letter 'g'
$ - anchor, word ending
and then get all words from dictionary which match this pattern:
Code:
using System.Linq;
using System.Text.RegularExpressions;
...
private static string[] Variants(string mask, IEnumerable<string> availableWords) {
Regex regex = new Regex("^" + Regex.Replace(mask, "#*", m => #$"\p{{L}}{{{m.Length}}}") + "$");
return availableWords
.Where(word => regex.IsMatch(availableWords))
.OrderBy(word => word)
.ToArray();
}
Demo:
string[] allWords = new [] {
"quick",
"brown",
"fox",
"jump",
"rating",
"coding"
"lazy",
"paring",
"fang",
"dog",
};
string[] variants = Variants("#a###g", allWords);
Console.Write(string.Join(Environment.NewLine, variants));
Outcome:
paring
rating
I need to find a word in a list with "a" at index 1 and "g" at index 5, like the following
wordList.Where(word => word.Length == 6 && word[1] == 'a' && word[5] == 'g')
The length check first will be critical to preventing a crash, unless your words are arranged into different lists by length..
If you mean that you literally will pass "#a###g" as the parameter that conveys the search term:
var term = "#a###g";
var search = term.Select((c,i) => (Chr:c,Idx:i)).Where(t => t.Chr != '#').ToArray();
var words = wordList.Where(word => word.Length == term.Length && search.All(t => word[t.Idx] == t.Chr));
How it works:
Take "#a###g" and project it to a sequence of the index of the char and the char itself, so ('#', 0),('a', 1),('#', 2),('#', 3),('#', 4),('g', 5)
Discard the '#', leaving only ('a', 1),('g', 5)
This means "'a' at position 1 and 'g' at 5"
Search the wordlist demanding that the word length is same as "#a###g", and also that All the search terms match when we "get the char out of the word at Idx and check it matches the Chr in the search term

Replacing Vowels with Numbers in a String Using C# or VB.Net

I'm trying to write an application that accept user input and then replaces the vowels a e i o u in the text with 1 2 3 4 5 respectively.
Example:
Inputted Text: Book
Output: B44k
oo replaced with a number.
Any help???
Preferably: C# or VB.NET
Well, I can't think of another attempt to explain this to you than to show you the solution:
inputString.Replace("a","1").Replace("e","2").Replace("i","3").Replace("o","4").Replace("u","5");
You could solve it a little bit more beautiful as well:
var vowels = new List<char> {'a', 'e', 'i', 'o', 'u'};
string.Join("", inputString.Select(c =>
{
var i = vowels.IndexOf(c);
return i == -1 ? c.ToString() : (i + 1).ToString();
}));
The first simply replaces each vowel, the second gets the index of the current character in the vowels (it's -1 if it didn't exist in the vowels) and, if it existed it adds 1 to it (I don't know why you didn't start to count with 0) and otherwise takes the normal character.
You can learn more about replace here.
Alternatively you could use a dictionary like that:
private static string ReplaceVowels (this string toReplace)
{
var vowels = new Dictionary<char, char> {{'a', '1'}, {'e', '2'}, {'i', '3'}, {'o', '4'}, {'u', '5'}};
return string.Join("", toReplace.Select (c => vowels.ContainsKey (c) ? vowels [c] : c));
}

Check if chars of a string contains in another string with LINQ

I'm making a Scrabble game in the command line with C#. The player must input some words like list below:
Word
Points
some
6
first
8
potsie
8
day
7
could
8
postie
8
from
9
have
10
back
12
this
7
The letters the player got are this:
sopitez
This value is a string. I'll check if the letters contains in the words. For this I've tried this code:
String highst = (from word
in words
where word.Contains(letters)
orderby points descending
select word).First();
But it doesn't work how I'll it. This code wouldn't select any word. I know the reason why because sopitez doesn't contain in any word.
My question now is there a way to check the chars in the string letters contain into the words whitout looping over the chars.
Note: Each letter must be used at most once in the solution.
If I calculate the result it must be potsie or postie. (I must write the logic for that)
P.S.: I'm playing this game: www.codingame.com/ide/puzzle/scrabble
This will not be performant at all but at least it will do the trick. Notice that I've used a dictionary just for the sake of simplicity (also I don't see why you would have repeated words like "potsie", I've never played scrabble). You can as well use a list of Tuples if you follow this code
EDIT: I changed this according to the OP's new comments
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var letters = new HashSet<char>("sopitez");
var wordsMap = new Dictionary<string, int>()
{
{"some", 6}, {"first", 8}, {"potsie", 8}, {"postie", 8}, {"day", 7},
{"could", 8}, {"from", 9}, {"have", 10}, {"back", 12},
{"this", 7}
};
var highest = wordsMap
.Select(kvp => {
var word = kvp.Key;
var points = kvp.Value;
var matchCount = kvp.Key.Sum(c => letters.Contains(c) ? 1 : 0);
return new {
Word = word,
Points = points,
MatchCount = matchCount,
FullMatch = matchCount == word.Length,
EstimatedScore = points * matchCount /(double) word.Length // This can vary... it's just my guess for an "Estiamted score"
};
})
.OrderByDescending(x => x.FullMatch)
.ThenByDescending(x => x.EstimatedScore);
foreach (var anon in highest)
{
Console.WriteLine("{0}", anon);
}
}
}
The problem here is that Contains checks to see if one string contains another; it is not checking to see if it contains all of those characters. You need to replace each string in your dictionary with a HashSet<char> and perform set comparisons like IsSubset or IsSuperset to determine if the letters are matching.
Here is what you're doing:
string a= "Hello";
string b= "elHlo";
bool doesContain = b.Contains(a); //This returns false
Here is what you need to do:
var setA = new HashSet<char>(a);
var setB = new HashSet<char>(b);
bool isSubset = a.IsSubsetOf(b); //This returns true
Update
Actually, this is wrong, because sets remove duplicate elements. But essentially you are misusing Contains. You'll need some more complicated sequence comparison that can allow duplicate letters.
Update2
You need this for word/letters comparison:
//Compares counts of each letter in word and tiles
bool WordCanBeMadeFromLetters(string word, string tileLetters) {
var tileLetterCounts = GetLetterCounts(tileLetters);
var wordLetterCounts = GetLetterCounts(word);
return wordLetterCounts.All(letter =>
tileLetterCounts.ContainsKey(letter.Key)
&& tileLetterCounts[letter.Key] >= letter.Value);
}
//Gets dictionary of letter/# of letter in word
Dictionary<char, int> GetLetterCounts(string word){
return word
.GroupBy(c => c)
.ToDictionary(
grp => grp.Key,
grp => grp.Count());
}
So your original example can look like this:
String highst = (from word
in words
where WordCanBeMadeFromLetters(word, letters)
orderby points descending
select word).First();
Since letters can repeat, I think you need something like this (of course that's not very efficient, but pure LINQ):
var letters = "sopitezwss";
var words = new Dictionary<string, int>() {
{"some", 6}, {"first", 8}, {"potsie", 8}, {"day", 7},
{"could", 8}, {"from", 9}, {"have", 10}, {"back", 12},
{"this", 7}, {"postie", 8}, {"swiss", 15}
};
var highest = (from word
in words
where word.Key.GroupBy(c => c).All(c => letters.Count(l => l == c.Key) >= c.Count())
orderby word.Value descending
select word);

How to check if a char array contains every element in another char array? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
LINQ: Check whether an Array is a subset of another
I am trying to determine if there is a way to use LINQ to find if every element in a subset array is in a superset array. For example with this superset:
{'w','o','k','r','d','o'}
The following would be a valid Subset:
{'o','k','w','r'}
While these would not be valid:
{'o','k','w','r','s'}
{'w','o','k','r','d','o','s'}
The actual superset is a char array that I have in memory. The actual subset is a value in a database table. I am trying to use LINQ to EF to get all values out of the table that meet this condition. This is what I have tried so far:
char[] letterArray = letters.ToCharArray();
return we.Words.Where(t => letterArray.Join(t.Word.ToCharArray(),
f => f,
s => s, (f, s) => new { s }).Count() == t.Word.Length
).Select(t => t.Word).ToArray();
But when I run this I get the error:
'Unable to create a constant value of type 'System.Char'. Only
primitive types ('such as Int32, String, and Guid') are supported in
this context.'
Is there a way around this error? Is there an easier way to do what I am trying here?
char[] t1 = {'w','o','k','r','d','o'};
char[] t2 = {'o','k','w','r'};
bool isSubset = !t2.Except(t1).Any();
LINQ has built in extensions like Except and Intersect for this kind of work.
char[] superset = { 'w', 'o', 'k', 'r', 'd', 'o' };
char[] subset1 = { 'o', 'k', 'w', 'r' };
char[] subset2 = { 'w', 'o', 'k', 'r', 'd', 'o', 's' };
bool subValid1 = !subset1.Except(superset).Any(); //true
bool subValid2 = !subset2.Except(superset).Any(); //false

Categories

Resources