First non-repeated character C# LINQ - c#

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
?? "";

Related

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);

Duplicated output when counting chars in a string with Linq

I have this problem with my output of this code which outputs how many times a character in a string is mentioned.
class Program
{
static void Main(string[] args)
{
string str = Console.ReadLine().ToLower();
string sortedString = String.Concat(str.OrderBy(c => c));
foreach (char ch in sortedString)
{
Console.WriteLine($"{ch} => {str.Count(x => x == ch)}");
}
}
}
This is the output I get:
Alabala
a => 4
a => 4
a => 4
a => 4
b => 1
l => 2
l => 2
This is the output I want to get
Alabala
a => 4
b => 1
l => 2
Would appreciate if somebody helps me out.
You can use combination of ToDictionary(), OrderBy() and Distinct() methods :
string str = "halleluyah";
var grouppedChars = str
.Distinct() // removes duplicates
.OrderBy(c => c) // orders them alphabetically
.ToDictionary( // converts to dictionary [string, int]
c => c,
c => str.Count(c2 => c2 == c));
foreach (var group in grouppedChars)
{
Console.WriteLine($"{group.Key} => {group.Value}");
}
Console.ReadKey();
Output :
a => 2
e => 1
h => 2
l => 3
u => 1
y => 1
P.S.
This is better then GroupBy() because you don't really want to keep this chars groupped somewhere but rather keep only count of them.
Method 2, add your own struct with char information :
struct CharStatistics
{
public readonly char #char;
public readonly int count;
public CharStatistics(char #char, int count)
{
this.#char = #char;
this.count = count;
}
}
In Main method :
string str = "halleluyah";
var charsInfo = str
.OrderBy(c => c)
.Distinct()
.Select(c =>
new CharStatistics(c, str.Count(c2 => c2 == c)));
foreach (var stats in charsInfo)
{
Console.WriteLine($"{stats.#char} => {stats.count}");
}
You can do this in single linq like below:
string str = Console.ReadLine().ToLower();
string sortedString = String.Concat(str.OrderBy(c => c));
var result = sortedString.GroupBy(x => x)
.Select(y => string.Format("{0} => {1}", y.Key, y.Count())).ToList();
foreach (var output in result)
{
Console.WriteLine(output);
}

How to find maximum number of repeated string in a string in a list of string in c#

If we have a list of strings, then how we can find the list of strings that have the maximum number of repeated symbol by using LINQ.
List <string> mylist=new List <string>();
mylist.Add("%1");
mylist.Add("%136%250%3"); //s0
mylist.Add("%1%5%20%1%10%50%8%3"); // s1
mylist.Add("%4%255%20%1%14%50%8%4"); // s2
string symbol="%";
List <string> List_has_MAX_num_of_symbol= mylist.OrderByDescending(s => s.Length ==max_num_of(symbol)).ToList();
//the result should be a list of s1 + s2 since they have **8** repeated '%'
I tried
var longest = mylist.Where(s => s.Length == mylist.Max(m => m.Length)) ;
this gives me only one string not both
Here's a very simple solution, but not exactly efficient. Every element has the Count operation performed twice...
List<string> mylist = new List<string>();
mylist.Add("%1");
mylist.Add("%136%250%3"); //s0
mylist.Add("%1%5%20%1%10%50%8%3"); // s1
mylist.Add("%4%255%20%1%14%50%8%4"); // s2
char symbol = '%';
var maxRepeat = mylist.Max(item => item.Count(c => c == symbol));
var longest = mylist.Where(item => item.Count(c => c == symbol) == maxRepeat);
It will return 2 strings:
"%1%5%20%1%10%50%8%3"
"%4%255%20%1%14%50%8%4"
Here is an implementation that depends upon SortedDictionary<,> to get what you're after.
var mylist = new List<string> {"%1", "%136%250%3", "%1%5%20%1%10%50%8%3", "%4%255%20%1%14%50%8%4"};
var mappedValues = new SortedDictionary<int, IList<string>>();
mylist.ForEach(str =>
{
var count = str.Count(c => c == '%');
if (mappedValues.ContainsKey(count))
{
mappedValues[count].Add(str);
}
else
{
mappedValues[count] = new List<string> { str };
}
});
// output to validate output
foreach (var str in mappedValues.Last().Value)
{
Console.WriteLine(str);
}
Here's one using LINQ that gets the result you're after.
var result = (from str in mylist
group str by str.Count(c => c == '%')
into g
let max = (from gKey in g select g.Key).Max()
select new
{
Count = max,
List = (from str2 in g select str2)
}).LastOrDefault();
OK, here's my answer:
char symbol = '%';
var recs = mylist.Select(s => new { Str = s, Count = s.Count(c => c == symbol) });
var maxCount = recs.Max(x => x.Count);
var longest = recs.Where(x => x.Count == maxCount).Select(x => x.Str).ToList();
It is complicated because it has three lines (the char symbol = '%'; line excluded), but it counts each string only once. EZI's answer has only two lines, but it is complicated because it counts each string twice. If you really want a one-liner, here it is:
var longest = mylist.Where(x => x.Count(c => c == symbol) == mylist.Max(y => y.Count(c => c == symbol))).ToList();
but it counts each string many times. You can choose whatever complexity you want.
We can't assume that the % is always going to be the most repeated character in your list. First, we have to determine what character appears the most in an individual string for each string.
Once we have the character and it maximum occurrence, we can apply Linq to the List<string> and grab the strings that contain the character equal to its max occurrence.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List <string> mylist=new List <string>();
mylist.Add("%1");
mylist.Add("%136%250%3");
mylist.Add("%1%5%20%1%10%50%8%3");
mylist.Add("%4%255%20%1%14%50%8%4");
// Determine what character appears most in a single string in the list
char maxCharacter = ' ';
int maxCount = 0;
foreach (string item in mylist)
{
// Get the max occurrence of each character
int max = item.Max(m => item.Count(c => c == m));
if (max > maxCount)
{
maxCount = max;
// Store the character whose occurrence equals the max
maxCharacter = item.Select(c => c).Where(c => item.Count(i => i == c) == max).First();
}
}
// Print the strings containing the max character
mylist.Where(item => item.Count(c => c == maxCharacter) == maxCount)
.ToList().ForEach(Console.WriteLine);
}
}
Results:
%1%5%20%1%10%50%8%3
%4%255%20%1%14%50%8%4
Fiddle Demo
var newList = myList.maxBy(x=>x.Count(y=>y.Equals('%'))).ToList();
This should work. Please correct syntax if wrong anywhere and update here too if it works for you.

Remove Alphabetic characters from a string, leaving numbers and symbols

I have a bunch of strings that I'm trying to parse the date out of. I have a script that will parse the date, but it's having trouble with all the extra letters in the string. I need to remove all the letters but leave characters such as - / _
I'm not particularly good with Regex, so all attempts to do this so far have ended with too many characters getting removed.
Here's a few sample strings to help:
Littleton, CO - Go-Live 5/8
Brunswick - Go-Live 5/14
CutSheeet_Go Live-5-14-14
Go Live - 5-19-2014
You could do this:
Regex.Replace(input, "([a-zA-Z,_ ]+|(?<=[a-zA-Z ])[/-])", "");
Working regex example:
http://regex101.com/r/kD2jF4
From your example data, output would be:
5/8
5/14
5-14-14
5-19-2014
You can use a function like this:
public static string Parse(string source)
{
var numbers = new [] {'0','1','2','3','4','5','6','7','8','9' };
var chars = new [] { '-', '/', '_' };
return new string(source
.Where(x => numbers.Contains(x) || chars.Contains(x))
.ToArray()).Trim(chars);
}
Here is fiddle
Try this:
public static string StripCrap(string input)
{
return input.Where(c => char.IsNumber(c) || c == '_' || c == '/' ||
c == '-').Aggregate("", (current, c) => current + c);
}
Or, if you want a maintainable list:
public static string StripCrap(string input)
{
char[] nonCrapChars = {'/', '-', '_'};
return input.Where(c => char.IsNumber(c) || nonCrapChars.Contains(c)).Aggregate("", (current, c) => current + c);
}
Or...You could also create an extension method:
public static string ToNonCrappyString(this string input)
{
char[] nonCrapChars = {'/', '-', '_'};
return input.Where(c => char.IsNumber(c) || nonCrapChars.Contains(c)).Aggregate("", (current, c) => current + c);
}
and you can call it like this:
string myString = "Hello 1234!";
string nonCrappyString = myString.ToNonCrappyString();
use this pattern .*?(\d+[\d-\/]*\d+)|.* and replace with $1 Demo

How to limit searching characters if I use LINQ

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();

Categories

Resources