How to limit searching characters if I use LINQ - c#

I have a function that returns duplicated (occur 2 or more times) characters in text. I do it with LINQ:
public char[] linq(string text)
{
char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key).ToArray();
return result;
}
But this way returns duplicated occurrences of all characters in the text (string). How to limit searching, if I want to search just English alphabet characters: abcdefghi....etc.
Thanx for help.

Something like this?
linq("and a rhino 11", new char[] { 'a', 'b', 'c' }); // result: { 'a' }
public char[] linq(string text, char[] limitChars)
{
char[] result = text
.Where( c => limitChars.Contains(c))
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToArray();
return result;
}
This solution only applies if you need to limit the character range to a configurable list.
Note that the char.IsLetter() method will allow characters from other alphabets (i.e. cyrillic, greek, etc.) to pass as well, so this might not be ideal.
Next best thing w/o passing a configurable list is #Femaref's solution imo explicitly using the character codes of the English alphabet - this might work best in your particular problem.

Looks like char.IsLetter() is what you want: char.IsLetter()

This is what you need.
// http://msdn.microsoft.com/en-us/library/system.char.isletter.aspx
private static void Main(string[] args)
{
Console.WriteLine(linq(#"szuizu_4156424324_hjvlahsjlvhlkd_&&ยง"));
Console.Read();
}
public static char[] linq(string text)
{
char[] result = text
.Where(Char.IsLetter)
.GroupBy(x => x)
.Where(g =>g.Count() > 1)
.Select(g => g.Key).ToArray();
return result;
}

char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1 && (g.Key >= 65 && g.Key <= 122))
.Select(g => g.Key).ToArray();
Update from comments:
char[] result = text
.GroupBy(x => x)
.Where(g => g.Count() > 1 && ((g.Key >= 65 && g.Key <= 90) || (g.Key >= 97 && g.Key <= 122)))
.Select(g => g.Key).ToArray();

Related

First non-repeated character C# LINQ

I've tried some answers from Stackoverflow but they don't count register of the symbols. For example
sTreSS => T (not 's'),
stress => t
Here is what i tried
public static char FirstNonRepeatedCharacter(string s)
{
var output = s.GroupBy(item => item).First(x => x.Count() == 1).Key;
return output;
}
I need to edit the code with case-insensitive and return the correct register
sEVeraL -> s; - SomeBody - S
This is exactly what you need, but not fully in LINQ. In my opinion, you don't have to strictly rely on LINQ...
Console.WriteLine(FirstNonRepeatedCharacter("sTreSS"));
Console.WriteLine(FirstNonRepeatedCharacter("stress"));
Console.WriteLine(FirstNonRepeatedCharacter("sEVeraL"));
Console.WriteLine(FirstNonRepeatedCharacter("SomeBody"));
Console.WriteLine(FirstNonRepeatedCharacter("AaBbCc"));
Console.ReadKey();
static char? FirstNonRepeatedCharacter(string s)
{
// Gather the count for each character (case insensitive, example: 's' and 'S' is in the same group).
var counts = new Dictionary<char, int>();
foreach (var ch in s.ToLower())
{
counts[ch] = counts.TryGetValue(ch, out var count)
? count + 1
: 1;
}
// Return first character with count 1.
return s.FirstOrDefault(ch => counts[char.ToLower(ch)] == 1);
}
Output is:
T
t
s
S
nothing (null)
You can group by characters as they are, but by processed character:
.GroupBy(c => char.ToLower(c), c => c)
Code:
// either first not repeating character or '\0'
private static char FirstNonRepeatedCharacter(string s) => s
?.GroupBy(c => char.ToLower(c), c => c)
?.FirstOrDefault(g => g.Count() == 1)
?.First()
?? '\0';
Edit: if you want to return string - "...I need to return an empty string..." -, you can group by string while providing required comparer:
private static string FirstNonRepeatedCharacter(string s) => s
?.GroupBy(c => c.ToString(), StringComparer.OrdinalIgnoreCase)
?.FirstOrDefault(g => g.Count() == 1)
?.Key
?? "";

C#:How to get the longest common prefix from a list of strings LINQ expression

I am trying to learn LINQ
I would like to understand how to get the longest common prefix from a list of strings
{"a","abC","abcD"}
would return "ab". Common as in at least 1 other string has it. Even though "a" is common for all 3, I would like to get "ab" because 2 elements share this prefix and "ab" is longer than "a"
It was an interesting challenge and this is my solution:
var array = new []{"a","abC","abcD"};
var longestCommonPrefix = Enumerable.Range(1, array.Max(_ => _)!.Length)
.Select(i =>
{
var grouped = array.Where(x => x.Length >= i)
.GroupBy(x => x[..i])
.Where(x => x.Count() > 1)
.OrderByDescending(x => x.Count())
.Select(x => new { LongestCommonPrefix = x.Key })
.FirstOrDefault();
return grouped?.LongestCommonPrefix ?? string.Empty;
}).Max();
var longestCommonPrefix = (words.FirstOrDefault() ?? String.Empty)
.Substring(0,
Enumerable.Range(0, words.Any() ? words.Min(x => x.Length) + 1 : 0)
.Where(x => words.Select(w => w.Substring(0, x))
.Distinct().Count() == 1).DefaultIfEmpty(0).Max()
);

create dictionary occurrences for each letter c#

We have a program that shows you how many times a letter is repeated in a text
string txt = input.text.ToLower();
txt = Regex.Replace(txt, #"\s+", "").Replace(")","").Replace("(","").Replace(".","").Replace(",","").Replace("!","").Replace("?","") ;
var letterCount = txt.Where(char.IsLetter).GroupBy(c => c).Select(v => new { Letter = v.Key, count = v.Count() });
foreach (var c in letterCount)
{
Debug.Log(string.Format("Caracterul:{0} apare {1} ori", c.Letter.ToString(), c.count));
}
And how do I give for the most repeating letter the value of 26, then for the one that repeats the less it gets 25 and for the one that only once a value in alphabetical order?
For example, the text "we are all happy"
Letter A is repeated three times and has the value of 26
For letter L 25
For P 24 and others in alphabetical order
And, finally, get their sum?
Sorry for my English!!!
You can use this LINQ approach:
string input = "we are all happy";
var allCharValues = input.ToLookup(c => c)
.Where(g => g.Key != ' ') // or you want spaces?
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // you mentioned alphabetical ordering if two have same count
.Select((x, index) => new { Char = x.Key, Value = 26 - index, Count = x.Count() });
foreach (var x in allCharValues)
Console.WriteLine($"Char:{x.Char} Value:{x.Value} Count:{x.Count}");
int sum = allCharValues.Select(x => x.Value).Sum();
In relation to your question about removing unwanted characters:
I think you'd be better of just keeping all characters between a and z. You could write an extension method to do this, and convert to lowercase at the same time:
public static class StringExt
{
public static string AlphabeticChars(this string self)
{
var alphabeticChars = self.Select(char.ToLower).Where(c => 'a' <= c && c <= 'z');
return new string(alphabeticChars.ToArray());
}
}
Then you can use an approach as follows. This is similar to Tim's approach, but this uses GroupBy() to count the occurrences; it also uses the new Tuple syntax from C#7 to simplify things. Note that this ALSO names the tuple properties, so they are not using the default Item1 and Item2.
string txt = "we, (are?) all! happy.";
var r = txt
.AlphabeticChars()
.GroupBy(c => c)
.Select(g => (Count: g.Count(), Char: g.Key))
.OrderByDescending(x => x.Count)
.ThenBy(x => x.Char)
.Select((v, i) => (Occurance: v, Index: 26-i));
int sum = r.Sum(c => c.Occurance.Count * c.Index);
Console.WriteLine(sum);

LINQ - Select min count

I have a list of strings which contain X in them. I want to select list(s) with the minimum count of X in them. For example:
CountMin("AXBXX", "AAX") will return AAX.
How can I write this qith LINQ in a concise way ?
public static string CountMin(IList<string> inputList)
{
if (inputList == null || !inputList.Any()) return null;
var result = inputList.Select(s => new
{
Item = s,
Count => s.Count(ch => ch == 'X')
})
.OrderBy(item => item.Count).First().Item;
}
Snippet assumes that all elements on list are different to null. If you need it, it could be easily improved.
You can also omit temporary class:
inputList.OrderBy(s => s.Count(c => c == 'X')).First();
string[] list = {"AXBXX", "AAX", "AXX"};
string result = (from word in list
select new { word, wordLen = (word.Length - (word.Replace("X", "")).Length) })
.OrderBy(x => x.wordLen).First().word;
MessageBox.Show(result);
Here's an answer that will get you all of the minimum X strings from the list.
var listOfStrings = new List<string>()
{
"AXB",
"ABXXC",
"ABX",
};
var minimumXs =
listOfStrings
.GroupBy(x => x.Count(y => y == 'X'))
.OrderBy(x => x.Key)
.Take(1)
.SelectMany(x => x);
That gives me:
AXB
ABX

How to initialize a string or char jagged array in C#?

Besides using a loop. An int array can be initialized with 0s easy like arr = Enumerable.Range(0, 100).Select(i => new int[100]).ToArray();.
Is there a way I can initialize a string or char array in a similar fashion?
I think you're looking for:
string[] arrayOfStringZeros = Enumerable.Range(0, 100)
.Select(i => "0")
.ToArray();
char[] arrayOfCharZeros = Enumerable.Range(0, 100)
.Select(i => '0')
.ToArray();
Updated
char[][] jaggedOfCharZeros = Enumerable.Range(0, 100)
.Select(i => Enumerable.Range(0, 100)
.Select(j => '0')
.ToArray())
.ToArray();
Actually it would probably be slightly more efficient to do:
char[] initZeros = Enumerable.Range(0, 100)
.Select(i => '0')
.ToArray();
char[][] jaggedOfCharZeros = Enumerable.Range(0, 100)
.Select(i => (char[])initZeros.Clone())
.ToArray();

Categories

Resources