LINQ C# Selecting characters from string - c#

I have a string that I convert to a char array and then I use LINQ to select the different characters inside the char array and then order them by Descending but only catch the characters, not the punctuation marks etc...
Here is the code:
string inputString = "The black, and, white cat";
var something = inputString.ToCharArray();
var txtEntitites = something.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.Where(e => Char.IsLetter(e)).Select(t=> t.Key);
And the error message I get:
Error CS1502: The best overloaded method match for `char.IsLetter(char)' has some invalid arguments (CS1502)
Error CS1503: Argument '#1' cannot convert 'System.Linq.IGrouping<char,char>' expression to type `char' (CS1503)
Any ideas? Thanks :)

Try this:
string inputString = "The black, and, white cat";
var something = inputString.ToCharArray();
var txtEntitites = something.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.Where(e => Char.IsLetter(e.Key))
.Select(t=> t.Key);
Note the Char.IsLetter(e.Key))
Another idea is to rearrange your query:
var inputString = "The black, and, white cat";
var txtEntitites = inputString.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.Select(t=> t.Key)
.Where(e => Char.IsLetter(e));
Also note you don't need the call to inputString.ToCharArray() since String is already an IEnumerable<Char>.

In your where clause, e in that context is your grouping, not the character. If you want to check if the character is a letter, you should be testing your key.
//...
.Where(g => Char.IsLetter(g.Key))

List<char> charArray = (
from c in inputString
where c >= 'A' && c <= 'z'
orderby c
select c
).Distinct()
.ToList();

I think this is what you are looking for
string inputString = "The black, and, white cat";
var something = inputString.ToCharArray();
var txtEntitites = something.Where(e => Char.IsLetter(e))
.GroupBy(c => c)
.OrderByDescending(g => g.Count()).Select(t=> t.Key);

Related

Sorting a formatted LINQ query

A sequence of non-empty strings stringList is given, containing only uppercase letters of the Latin alphabet. For all strings starting with the same letter, determine their total length and obtain a sequence of strings of the form "S-C", where S is the total length of all strings from stringList that begin with the character C. Order the resulting sequence in descending order of the numerical values of the sums, and for equal values of the sums, in ascending order of the C character codes.
This question is related to one of my previous questions.
One solution that works is this one:
stringList.GroupBy(x => x[0]).Select(g => $"{g.Sum(x => x.Length)}-{g.Key}");
The problem is that with this given example I don't know where to add the OrderByDescending()/ThenBy() clauses in order to get the correctly sorted list.
Create an intermediate data structure to store needed info and use it for sorting and then building the output:
stringList
.GroupBy(x => x[0])
.Select(g => (Length: g.Sum(x => x.Length), Char: g.Key))
.OrderByDescending(t => t.Length)
.ThenBy(t => t.Char)
.Select(t => $"{t.Length}-{t.Char}");
You're almost there. The cleanest way of doing it would be to make a more complex object with the properties you care about, use those to sort, then keep only what you want in the output. Like:
stringList
.GroupBy(x => x[0])
.Select(g => new {
Len = g.Sum(x => x.Length),
Char = g.Key,
Val = $"{g.Sum(x => x.Length)}-{g.Key}"
})
.OrderByDescending(x => Len)
.ThenBy(x => x.Char)
.Select(x => x.Val);
You can add a Select after the GroupBy to transform the groups into an anonymous object containing the things you want to sort by. Then you can use OrderByDescending and ThenBy to sort. After that, Select the formatted string you want:
stringList.GroupBy(x => x[0]) // assuming all strings are non-empty
.Select(g => new {
LengthSum = g.Sum(x => x.Length),
FirstChar = g.Key
})
.OrderByDescending(x => x.LengthSum)
.ThenBy(x => x.FirstChar)
.Select(x => $"{x.LengthSum}-{x.FirstChar}");
Alternatively, do it in the query syntax with let clauses, which I find more readable:
var query = from str in stringList
group str by str[0] into g
let lengthSum = g.Sum(x => x.Length)
let firstChar = g.Key
orderby lengthSum descending, firstChar
select $"{lengthSum}-{firstChar}";

Extract values from a string into arrays

I have a string like this:
john "is my best buddy" and he loves "strawberry juice"
I want to-
Extract texts within double-quotes into a string array array1
Split texts outside of double-quotes by spaces and then insert them into another string array (array2).
Output:
array1[0]: is my best buddy
array1[1]: strawberry juice
array2[0]: john
array2[1]: and
array2[2]: he
array2[3]: loves
Any help is appreciated.
Clearly, this is a call for Regular Expressions:
var str = #"john ""is my best buddy"" and he loves ""strawberry juice""";
var regex = new Regex("(\"(?'quoted'[^\"]+)\")|(?'word'\\w+)",
RegexOptions.Singleline|RegexOptions.Compiled);
var matches = regex.Matches(str);
var quotes = matches.Cast<Match>()
.SelectMany(m => m.Groups.Cast<Group>())
.Where(g => g.Name == "quoted" && g.Success)
.Select(g => g.Value)
.ToArray();
var words = matches.Cast<Match>()
.SelectMany(m => m.Groups.Cast<Group>())
.Where(g => g.Name == "word" && g.Success)
.Select(g => g.Value)
.ToArray();

The most common word in spaceless string

I have a very long string of text that is many words separated by camelCase like so:
AedeagalAedilityAedoeagiAefaldnessAegeriidaeAeginaAeipathyAeneolithicAeolididaeAeonialAerialityAerinessAerobia
I need to find the most common word and the number of times it has been used, I am unaware how to do this due to the lack of spaces and being new to C#.
I have tried many methods but none seem to work, any advice you have I'd be very grateful.
I have a github repo with the file being downloaded and a few tests already done here: https://github.com/Imstupidpleasehelp/C-code-test
Thank you.
You can try querying the string with a help of regular expressions and Linq:
string source = ...
var result = Regex
.Matches(source, "[A-Z][a-z]*")
.Cast<Match>()
.Select(match => match.Value)
.GroupBy(word => word)
.Select(group => (word : group.Key, count : group.Count()))
.OrderByDescending(pair => pair.count)
.First();
Console.Write($"{result.word} appears {result.count} time");
string[] split = Regex.Split(exampleString, "(?<=[A-Za-z])(?=[A-Z][a-z])");
var result = split.GroupBy(s => s)
.Where(g=> g.Count()>=1 )
.OrderByDescending(g => g.Count())
.Select(g => new{ Word = g.Key, Occurrences = g.Count()});
var result will contain pairs of (Word, Occurrences) for all words.
If you want just the first one (the one with the most occurrences) use
var result = split.GroupBy(s => s)
.Where(g=> g.Count()>=1 )
.OrderByDescending(g => g.Count())
.Select(g => new{ Word = g.Key, Occurrences = g.Count()}).First();
Have in mind that it can happen that you have 2 or more words with the same number of occurrences, so using First() would only give you one of those.
A non-linq approach using for loop and IsUpper to separate the words.
string data = "AedeagalAedilityAedoeagiAefaldness";
var words = new List<string>();
var temp = new StringBuilder();
for(int i = 0;i < data.Length;i++)
{
temp.Append(data[i]);
if (i == data.Length-1 || char.IsUpper(data[i+1]))
{
words.Add(temp.ToString());
temp.Clear();
}
}

Check if String Contains Match in Enumerable.Range Filter List

I want to check if a string contains a word or number from a list and remove it from the string.
I want to use Enumerable.Range() to create the filter list and use it to filter many different strings.
I'm trying to combine two previous answers:
https://stackoverflow.com/a/49733139/6806643
https://stackoverflow.com/a/49740832/6806643
The sentence I want to filter:
This is a A05B09 hello 02 100 test
Filter
A00B00-A100B100, 01-100, 000-100, hello
Should read:
This is a test
Old Way
For Loop - Works
http://rextester.com/BJL70824
New Way
Enumerable Range List - Does not work
http://rextester.com/ZSCM64375
C#
List<List<string>> filters = Enumerable.Range(0, 101)
.SelectMany(a => Enumerable.Range(0, 101).Select(b => "A{0:00}B{1:00}"))
.Select(i => Enumerable.Range(0, 10).Select(c => string.Empty).ToList())
.SelectMany(a => Enumerable.Range(0, 101).Select(b => "{0:000}"))
.SelectMany(a => Enumerable.Range(0, 101).Select(b => "{0:00}"))
.SelectMany(a => Enumerable.Range(0, 1).Select(b => "hello"))
.ToList();
List<string> matches = new List<string>();
// Sentence
string sentence = "This is a A05B09 hello 02 100 test";
string newSentence = string.Empty;
// Find Matches
for (int i = 0; i < filters.Count; i++)
{
// Add to Matches List
if (sentence.Contains(filters[i].ToString()))
{
matches.Add(filters[i]);
}
}
// Filter Sentence
newSentence = Regex.Replace(
sentence
, #"(?<!\S)(" + string.Join("|", matches) + #")(?!\S)"
, ""
, RegexOptions.IgnoreCase
);
// Display New Sentence
Console.WriteLine(newSentence);
I think creating a list of all possible combinations is a very bad approach. You are creating huge lists which will make your process use a lot of RAM and be very slow without any good reason. Why not just create a good Regex? For example, with this expression, you get your desired string:
\b(A\d\dB\d\d|A100B100|0?\d\d|100|hello)\b\s*
That is assuming you don't want to replace stuff like A101B101 or 123.
If you want to replace those as well, the regex is a bit simpler:
\b(A\d\d\d?B\d\d\d?|\d\d\d?|hello)\b\s*
Your this line seems not meet your requirements..SelectMany(a => Enumerable.Range(0, 101).Select(b => "A{0:00}B{1:00}"))
Can you try this Linq?
List<string> filters = Enumerable.Range(0, 101)
.SelectMany(a => Enumerable.Range(0, 101).Select(b => $"A{a:00}B{b:00}"))
.Union(Enumerable.Range(0, 101).Select(b => $"{b:000}"))
.Union(Enumerable.Range(0, 101).Select(b => $"{b:00}"))
.Union(new List<string> {"hello"})
.ToList();
This verion can give you expected result on rextester
List<string> filters = Enumerable.Range(0, 101)
.SelectMany(a => Enumerable.Range(0, 101).Select(b => string.Format("A{0:00}B{1:00}", a, b)))
.Union(Enumerable.Range(0, 101).Select(b => string.Format("{0:000}", b)))
.Union(Enumerable.Range(0, 101).Select(b => string.Format("{0:00}", b)))
.Union(new List<string> { "hello" })
.ToList();

making an char array out of string array

Here I have an array. I want to group them by their first letter, and then take out the strings that begins with a and b, char array them.
the following is my attempt:
string[] ab = { "aa", "ab", "bb", "bc", "cd", "ce" };
var aq = ab.GroupBy(i => i[0]).Where(x => x.Key == 'a' && x.Key == 'b').SelectMany(x => x.Value.ToCharArray());
My Problem here is at my last statement, i cant get x.Value which is strange since it belongs to igroup
Also I would like to get a char array answer something like { a,a,a,b,b,b,b,c}
Try this:
var aq = ab.Where(it => it.StartsWith("a") || it.StartsWith("b"))
.SelectMany(it => it.ToCharArray());
First you select the strings that start with 'a' OR 'b', then you turn them into char arrays and concatenate them.
You can accomplish what you want without a GroupBy(), by checking the first character of each string:
var result = ab
.Where(x => x.ToLower()[0] == 'a'
|| x.ToLower()[0] == 'b')
.SelectMany(x => x)
.ToArray();
Please not this will break if you have any null values in your list.
You can also use the StartsWith() extension and pass in the boolean parameter to ignore case along with the culture info:
var result = ab
.Where(x => x.StartsWith("a", true, System.Globalization.CultureInfo.CurrentCulture)
|| x.StartsWith("b", true, System.Globalization.CultureInfo.CurrentCulture))
.SelectMany(x => x)
.ToArray();
Fiddle here

Categories

Resources