Find the first non-repeated character in a string using C# - c#

I am working to solve this problem. I have to find the first nonrepeated character in a string.
For example,
Input : “teeter”
Output: r
I am going to first use HashTables :
class Program
{
static void Main()
{
var inputString = “teeter” ;
Hashtable hashtable = new Hashtable();
int numb = 1;
for (int i=0; i< inputString.length(); i++)
{
if (!hashtable.ContainsKey(hashtable[i]))
hashtable.Add(hashtable[i], numb);
else
hashtable[hashtable[i]] = hashtable[i].Value+ 1 ;
}
}
}
Can I solve this problem using LinQ:
numb = inputString.First(1 == inputString.Where(item =>
item == hashtable[i]).Count());
My questions are :
-I have to solve this problem using LINQ and using HashTables or Dictionaries. Does my solutions ture ?

// throws an ArgumentNullException if s is null.
// throws an InvalidOperationException if there is no non repeating character.
char FirstNonRepeater(string s)
{
return s.ToLookup(c => c).First(g => g.Count() == 1).Key;
}

I don't think you need HashTable at all. Because string implements IEnumerable<char> you can use LINQ directly on your input string:
var letter = input.GroupBy(x => x).First(g => g.Count() == 1).Key;
Getting back to your HashTable solution. You 're not using it correctly. HashTable is not the same as Dictionary. It does not have key/value, it just has keys. You're looking for Dictionary here:
var inputString = "teeter";
var dict = new Dictionary<char, int>();
int numb = 1;
for (int i=0; i< inputString.length(); i++)
{
if (!dict.ContainsKey(inputString[i]))
dict.Add(inputString[i], numb);
else
dict[inputString[i]] += 1;
}

For a solution without HashTables, Dictionaries or LINQ, just remove duplicate characters from the string:
while (s.IndexOf(s[0], 1) != -1) {
s = s.Replace(s[0].ToString(), "");
}
char result = s[0];

You can check which characters are occured only once, and take first one out of these.
var inputString = “teeter” ;
var output = inputString.GroupBy(x=>x).FirstOrDefault(x=>x.Count() ==1).Key;

class Program
{
public static void Main(string[] args)
{
Console.WriteLine(FirstNonRepeated("tether"));
Console.ReadKey();
}
public static char? FirstNonRepeated(string word)
{
char[] chararray= word.ToCharArray();
Hashtable hashtable=new Hashtable();
foreach (var c in chararray)
{
if (hashtable.ContainsKey(c))
{
hashtable[c]=(int)hashtable[c]+1;
}
else
{
hashtable.Add(c,1);
}
}
foreach (var v in chararray)
{
if ((int) hashtable[v] == 1)
{
return v;
}
}
return null;
}
}

Related

Compare strings for equality

I want to compare a collection of strings and return the the equal parts until a not equal part occurs. (and remove traling whitespace).
example:
List<string> strList = new List<string>
{
"string xyz stop",
"string abc stop",
"string qrt stop"
};
string result = GetEqualName(strList); // This should return "string"
I made the following method that works
string GetEqualName(IEnumerable<string> strList)
{
string outString = "";
bool firstTime = true;
foreach (var subString in strList)
{
if (firstTime)
{
outString = subString;
firstTime = false;
}
else
{
string stringBuilder = "";
for (int i = 0; i < outString.Count(); i++)
{
if (outString[i] == subString[i])
stringBuilder = stringBuilder + outString[i];
else
break;
}
outString = stringBuilder;
}
}
outString = outString.TrimEnd(' '); // Remove traling whitespace
return outString;
}
I just feel that this is something that can be done in a few lines and I am overdoing it. Do you guys have any suggestions?
You can Zip two strings together, take the pairs that are equal, and then create a string of those characters.
public static string LargestCommonPrefix(string first, string second)
{
return new string(first.Zip(second, Tuple.Create)
.TakeWhile(pair => pair.Item1 == pair.Item2)
.Select(pair => pair.Item1)
.ToArray());
}
Once you've solved the problem for the case of combining two strings, you can easily apply it to a sequence of strings:
public static string LargestCommonPrefix(IEnumerable<string> strings)
{
return strings.Aggregate(LargestCommonPrefix);
}
This little function does basically the same as your version, but shorter.
string GetEqualName(IEnumerable<string> strList)
{
int limit = strList.Min(s => s.Length);
int i = 0;
for (; i < limit; i++)
{
if (strList.Select(s => s.Substring(0,i+1)).Distinct().Count() > 1)
{
break;
}
}
return strList.First().Substring(0, i).Trim();
}
Here's a different method which does what you want. I looks for the longest common substring from left to right using a HashSet<string>:
string GetCommonStartsWith(IEnumerable<string> strList, StringComparer comparer = null)
{
if(!strList.Any() || strList.Any(str => string.IsNullOrEmpty(str)))
return null;
if(!strList.Skip(1).Any())
return strList.First(); // only one
if(comparer == null) comparer = StringComparer.CurrentCulture;
int commonLength = strList.Min(str => str.Length);
for (int length = commonLength; length > 0; length--)
{
HashSet<string> duptester = new HashSet<string>(comparer);
string first = strList.First().Substring(0, length).TrimEnd();
duptester.Add(first);
bool allEqual = strList.Skip(1)
.All(str => !duptester.Add(str.Substring(0, length).TrimEnd()));
if (allEqual)
return first;
}
return null;
}
Here's a version that uses less LINQ than some of the other answers and might possibly be more performant.
string GetEqualName(IEnumerable<string> strList)
{
StringBuilder builder = new StringBuilder();
int minLength = strList.Min(s => s.Length);
for (int i = 0; i < minLength; i++)
{
char? c = null;
foreach (var s in strList)
{
if (c == null)
c = s[i];
else if (s[i] != c)
return builder.ToString().TrimEnd();
}
builder.Append(c);
}
return builder.ToString().TrimEnd();
}

Locating items in List whether they occur more than once in C#

In addition to the question: Get List<> element position in c# using LINQ
First of all, let me explaing why I do what I do :)
I'm trying to encrypt a string into a one-line code which holds how many times a letter is used in the string and also with its positions. By this method, I'll be able to decrypt the code and get(reproduce) the full text again. Let's say myString is "How are you today". I'll encrypt it like
o3[1,9,13]," "3[3,7,11],a2[4,15],y2[9,17],H1[0],w1[2],r1[5],e1[6],u1[10],t1[12],d1[14],?[18]
I know it looks odd but think about working on bigger strings like e-books. This could handle all the text in one or two lines.
The encryption is not about the security, it's just about holding big datas in smaller spaces.
In my code, I can convert the string into list, count how many times a letter is used but I can't define the positions of the letters when they occur more than once.
private void btnKoda_Click(object sender, EventArgs e)
{
var yazi = txtYazi.Text;
List<char> liste = yazi.ToList();
List<string> tut = new List<string>();
foreach (char harf in liste)
{
for (int i = 0; i < liste.Count; i++)
{
char ekle = liste[i];
tut.Add(ekle.ToString());
}
foreach (var karakter in tut)
{
txtKod.Text += karakter;
}
// holds statics
var istatistik =
from c in tut
group c by c into g
select new { g.Key, say = g.Count() };
var enCok =
from giris in istatistik
orderby giris.say descending
select giris;
foreach (var giris in enCok)
{
txtHarfler.Text += string.Format("{0}: {1}\r\n", giris.Key, giris.say);
}
break;
}
Not sure what's going on in your code, but here's how I would do it:
private void button1_Click(object sender, EventArgs e)
{
Dictionary<Char, Encoding> dct = new Dictionary<char, Encoding>();
string data = "How are you today";
for(int i = 0; i < data.Length; i++)
{
Char C = data[i];
if (!dct.ContainsKey(C))
{
dct.Add(C, new Encoding(C));
}
dct[C].AddOccurence(i);
}
StringBuilder SB = new StringBuilder();
foreach(Encoding enc in dct.Values)
{
if (SB.Length == 0)
{
SB.Append(enc.ToString());
}
else
{
SB.Append("," + enc.ToString());
}
}
Console.WriteLine(SB.ToString());
}
Here's the Encoding class:
public class Encoding
{
private Char _C;
private List<int> _Positions;
private Encoding() {}
public Encoding(Char C)
{
this._C = C;
this._Positions = new List<int>();
}
public Char Character
{
get
{
return _C;
}
}
public int Count
{
get
{
return _Positions.Count;
}
}
public int[] Occurences
{
get
{
return _Positions.ToArray();
}
}
public override string ToString()
{
string[] values = Array.ConvertAll(this.Occurences.ToArray(), x => x.ToString());
return this.Character.ToString() + this.Count.ToString() + "[" + String.Join(",", values) + "]";
}
public void AddOccurence(int position)
{
this._Positions.Add(position);
}
}
Original String:
How are you today
Output:
H1[0],o3[1,9,13],w1[2], 3[3,7,11],a2[4,15],r1[5],e1[6],y2[8,16],u1[10],t1[12],d1[14]

Replace every other of a certain char in a string

I have searched a lot to find a solution to this, but could not find anything. I do however suspect that it is because I don't know what to search for.
First, I have a string that I convert to an array. The string will be formatted like so:
"99.28099822998047,68.375 118.30699729919434,57.625 126.49999713897705,37.875 113.94499683380127,11.048999786376953 96.00499725341797,8.5"
I create the array with the following code:
public static Array StringToArray(string String)
{
var list = new List<string>();
string[] Coords = String.Split(' ', ',');
foreach (string Coord in Coords)
{
list.Add(Coord);
}
var array = list.ToArray();
return array;
}
Now my problem is; I am trying to find a way to convert it back into a string, with the same formatting. So, I could create a string simply using:
public static String ArrayToString(Array array)
{
string String = string.Join(",", array);
return String;
}
and then hopefully replace every 2nd "," with a space (" "). Is this possible? Or are there a whole other way you would do this?
Thank you in advance! I hope my question makes sense.
There is no built-in way of doing what you need. However, it's pretty trivial to achieve what it is you need e.g.
public static string[] StringToArray(string str)
{
return str.Replace(" ", ",").Split(',');
}
public static string ArrayToString(string[] array)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= array.Length-1; i++)
{
sb.AppendFormat(i % 2 != 0 ? "{0} " : "{0},", array[i]);
}
return sb.ToString();
}
If those are pairs of coordinates, you can start by parsing them like pairs, not like separate numbers:
public static IEnumerable<string[]> ParseCoordinates(string input)
{
return input.Split(' ').Select(vector => vector.Split(','));
}
It is easier then to reconstruct the original string:
public static string PrintCoordinates(IEnumerable<string[]> coords)
{
return String.Join(" ", coords.Select(vector => String.Join(",", vector)));
}
But if you absolutely need to have your data in a flat structure like array, it is then possible to convert it to a more structured format:
public static IEnumerable<string[]> Pairwise(string[] coords)
{
coords.Zip(coords.Skip(1), (coord1, coord2) => new[] { coord1, coord2 });
}
You then can use this method in conjunction with PrintCoordinates to reconstruct your initial string.
Here is a route to do it. I don't think other solutions were removing last comma or space. I also include a test.
public static String ArrayToString(Array array)
{
var useComma = true;
var stringBuilder = new StringBuilder();
foreach (var value in array)
{
if (useComma)
{
stringBuilder.AppendFormat("{0}{1}", value, ",");
}
else
{
stringBuilder.AppendFormat("{0}{1}", value, " ");
}
useComma = !useComma;
}
// Remove last space or comma
stringBuilder.Length = stringBuilder.Length - 1;
return stringBuilder.ToString();
}
[TestMethod]
public void ArrayToStringTest()
{
var expectedStringValue =
"99.28099822998047,68.375 118.30699729919434,57.625 126.49999713897705,37.875 113.94499683380127,11.048999786376953 96.00499725341797,8.5";
var array = new[]
{
"99.28099822998047",
"68.375",
"118.30699729919434",
"57.625",
"126.49999713897705",
"37.875",
"113.94499683380127",
"11.048999786376953",
"96.00499725341797",
"8.5",
};
var actualStringValue = ArrayToString(array);
Assert.AreEqual(expectedStringValue, actualStringValue);
}
Another way of doing it:
string inputString = "1.11,11.3 2.22,12.4 2.55,12.8";
List<string[]> splitted = inputString.Split(' ').Select(a => a.Split(',')).ToList();
string joined = string.Join(" ", splitted.Select(a => string.Join(",",a)).ToArray());
"splitted" list will look like this:
1.11 11.3
2.22 12.4
2.55 12.8
"joined" string is the same as "inputString"
Here's another approach to this problem.
public static string ArrayToString(string[] array)
{
Debug.Assert(array.Length % 2 == 0, "Array is not dividable by two.");
// Group all coordinates as pairs of two.
int index = 0;
var coordinates = from item in array
group item by index++ / 2
into pair
select pair;
// Format each coordinate pair with a comma.
var formattedCoordinates = coordinates.Select(i => string.Join(",", i));
// Now concatinate all the pairs with a space.
return string.Join(" ", formattedCoordinates);
}
And a simple demonstration:
public static void A_Simple_Test()
{
string expected = "1,2 3,4";
string[] array = new string[] { "1", "2", "3", "4" };
Debug.Assert(expected == ArrayToString(array));
}

Splitting a string array

I have a string array string[] arr, which contains values like N36102W114383, N36102W114382 etc...
I want to split the each and every string such that the value comes like this N36082 and W115080.
What is the best way to do this?
This should work for you.
Regex regexObj = new Regex(#"\w\d+"); # matches a character followed by a sequence of digits
Match matchResults = regexObj.Match(subjectString);
while (matchResults.Success) {
matchResults = matchResults.NextMatch(); #two mathches N36102 and W114383
}
If you have the fixed format every time you can just do this:
string[] split_data = data_string.Insert(data_string.IndexOf("W"), ",")
.Split(",", StringSplitOptions.None);
Here you insert a recognizable delimiter into your string and then split it by this delimiter.
Forgive me if this doesn't quite compile, but I'd just break down and write the string processing function by hand:
public static IEnumerable<string> Split(string str)
{
char [] chars = str.ToCharArray();
int last = 0;
for(int i = 1; i < chars.Length; i++) {
if(char.IsLetter(chars[i])) {
yield return new string(chars, last, i - last);
last = i;
}
}
yield return new string(chars, last, chars.Length - last);
}
If you use C#, please try:
String[] code = new Regex("(?:([A-Z][0-9]+))").Split(text).Where(e => e.Length > 0 && e != ",").ToArray();
in case you're only looking for the format NxxxxxWxxxxx, this will do just fine :
Regex r = new Regex(#"(N[0-9]+)(W[0-9]+)");
Match mc = r.Match(arr[i]);
string N = mc.Groups[1];
string W = mc.Groups[2];
Using the 'Split' and 'IsLetter' string functions, this is relatively easy in c#.
Don't forget to write unit tests - the following may have some corner case errors!
// input has form "N36102W114383, N36102W114382"
// output: "N36102", "W114383", "N36102", "W114382", ...
string[] ParseSequenceString(string input)
{
string[] inputStrings = string.Split(',');
List<string> outputStrings = new List<string>();
foreach (string value in inputstrings) {
List<string> valuesInString = ParseValuesInString(value);
outputStrings.Add(valuesInString);
}
return outputStrings.ToArray();
}
// input has form "N36102W114383"
// output: "N36102", "W114383"
List<string> ParseValuesInString(string inputString)
{
List<string> outputValues = new List<string>();
string currentValue = string.Empty;
foreach (char c in inputString)
{
if (char.IsLetter(c))
{
if (currentValue .Length == 0)
{
currentValue += c;
} else
{
outputValues.Add(currentValue);
currentValue = string.Empty;
}
}
currentValue += c;
}
outputValues.Add(currentValue);
return outputValues;
}

compare the characters in two strings

In C#, how do I compare the characters in two strings.
For example, let's say I have these two strings
"bc3231dsc" and "bc3462dsc"
How do I programically figure out the the strings
both start with "bc3" and end with "dsc"?
So the given would be two variables:
var1 = "bc3231dsc";
var2 = "bc3462dsc";
After comparing each characters from var1 to var2, I would want the output to be:
leftMatch = "bc3";
center1 = "231";
center2 = "462";
rightMatch = "dsc";
Conditions:
1. The strings will always be a length of 9 character.
2. The strings are not case sensitive.
The string class has 2 methods (StartsWith and Endwith) that you can use.
After reading your question and the already given answers i think there are some constraints are missing, which are maybe obvious to you, but not to the community. But maybe we can do a little guess work:
You'll have a bunch of string pairs that should be compared.
The two strings in each pair are of the same length or you are only interested by comparing the characters read simultaneously from left to right.
Get some kind of enumeration that tells me where each block starts and how long it is.
Due to the fact, that a string is only a enumeration of chars you could use LINQ here to get an idea of the matching characters like this:
private IEnumerable<bool> CommonChars(string first, string second)
{
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
var charsToCompare = first.Zip(second, (LeftChar, RightChar) => new { LeftChar, RightChar });
var matchingChars = charsToCompare.Select(pair => pair.LeftChar == pair.RightChar);
return matchingChars;
}
With this we can proceed and now find out how long each block of consecutive true and false flags are with this method:
private IEnumerable<Tuple<int, int>> Pack(IEnumerable<bool> source)
{
if (source == null)
throw new ArgumentNullException("source");
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
bool current = iterator.Current;
int index = 0;
int length = 1;
while (iterator.MoveNext())
{
if(current != iterator.Current)
{
yield return Tuple.Create(index, length);
index += length;
length = 0;
}
current = iterator.Current;
length++;
}
yield return Tuple.Create(index, length);
}
}
Currently i don't know if there is an already existing LINQ function that provides the same functionality. As far as i have already read it should be possible with SelectMany() (cause in theory you can accomplish any LINQ task with this method), but as an adhoc implementation the above was easier (for me).
These functions could then be used in a way something like this:
var firstString = "bc3231dsc";
var secondString = "bc3462dsc";
var commonChars = CommonChars(firstString, secondString);
var packs = Pack(commonChars);
foreach (var item in packs)
{
Console.WriteLine("Left side: " + firstString.Substring(item.Item1, item.Item2));
Console.WriteLine("Right side: " + secondString.Substring(item.Item1, item.Item2));
Console.WriteLine();
}
Which would you then give this output:
Left side: bc3
Right side: bc3
Left side: 231
Right side: 462
Left side: dsc
Right side: dsc
The biggest drawback is in someway the usage of Tuple cause it leads to the ugly property names Item1 and Item2 which are far away from being instantly readable. But if it is really wanted you could introduce your own simple class holding two integers and has some rock-solid property names. Also currently the information is lost about if each block is shared by both strings or if they are different. But once again it should be fairly simply to get this information also into the tuple or your own class.
static void Main(string[] args)
{
string test1 = "bc3231dsc";
string tes2 = "bc3462dsc";
string firstmatch = GetMatch(test1, tes2, false);
string lasttmatch = GetMatch(test1, tes2, true);
string center1 = test1.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;
string center2 = test2.Substring(firstmatch.Length, test1.Length -(firstmatch.Length + lasttmatch.Length)) ;
}
public static string GetMatch(string fist, string second, bool isReverse)
{
if (isReverse)
{
fist = ReverseString(fist);
second = ReverseString(second);
}
StringBuilder builder = new StringBuilder();
char[] ar1 = fist.ToArray();
for (int i = 0; i < ar1.Length; i++)
{
if (fist.Length > i + 1 && ar1[i].Equals(second[i]))
{
builder.Append(ar1[i]);
}
else
{
break;
}
}
if (isReverse)
{
return ReverseString(builder.ToString());
}
return builder.ToString();
}
public static string ReverseString(string s)
{
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
Pseudo code of what you need..
int stringpos = 0
string resultstart = ""
while not end of string (either of the two)
{
if string1.substr(stringpos) == string1.substr(stringpos)
resultstart =resultstart + string1.substr(stringpos)
else
exit while
}
resultstart has you start string.. you can do the same going backwards...
Another solution you can use is Regular Expressions.
Regex re = new Regex("^bc3.*?dsc$");
String first = "bc3231dsc";
if(re.IsMatch(first)) {
//Act accordingly...
}
This gives you more flexibility when matching. The pattern above matches any string that starts in bc3 and ends in dsc with anything between except a linefeed. By changing .*? to \d, you could specify that you only want digits between the two fields. From there, the possibilities are endless.
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
class Sample {
static public void Main(){
string s1 = "bc3231dsc";
string s2 = "bc3462dsc";
List<string> common_str = commonStrings(s1,s2);
foreach ( var s in common_str)
Console.WriteLine(s);
}
static public List<string> commonStrings(string s1, string s2){
int len = s1.Length;
char [] match_chars = new char[len];
for(var i = 0; i < len ; ++i)
match_chars[i] = (Char.ToLower(s1[i])==Char.ToLower(s2[i]))? '#' : '_';
string pat = new String(match_chars);
Regex regex = new Regex("(#+)", RegexOptions.Compiled);
List<string> result = new List<string>();
foreach (Match match in regex.Matches(pat))
result.Add(s1.Substring(match.Index, match.Length));
return result;
}
}
for UPDATE CONDITION
using System;
class Sample {
static public void Main(){
string s1 = "bc3231dsc";
string s2 = "bc3462dsc";
int len = 9;//s1.Length;//cond.1)
int l_pos = 0;
int r_pos = len;
for(int i=0;i<len && Char.ToLower(s1[i])==Char.ToLower(s2[i]);++i){
++l_pos;
}
for(int i=len-1;i>0 && Char.ToLower(s1[i])==Char.ToLower(s2[i]);--i){
--r_pos;
}
string leftMatch = s1.Substring(0,l_pos);
string center1 = s1.Substring(l_pos, r_pos - l_pos);
string center2 = s2.Substring(l_pos, r_pos - l_pos);
string rightMatch = s1.Substring(r_pos);
Console.Write(
"leftMatch = \"{0}\"\n" +
"center1 = \"{1}\"\n" +
"center2 = \"{2}\"\n" +
"rightMatch = \"{3}\"\n",leftMatch, center1, center2, rightMatch);
}
}

Categories