Add incremental alphabetic & numeric chars to string - c#

I need to a method (or 2?) that add suffixes to a string.
Let's say I have the string "Hello".
If I click option 1 it should create a list of strings such as
Hello a
Hello b
Hello c
I've got that part covered.
The next option I'd need it to create a list such as
Hello aa
Hello ab
Hello ac
...
Hello ba
Hello bb
Hello bc
and so on....
Also...each option has 2 other options..
Say I want to add suffix 1 as a-z and suffix 2 as 0-9
Then it'd be
Hello a0
Hello a1
Is there anyone that can help me? This is how I do a single letter increment.
if (ChkSuffix.Checked)
{
if (CmbSuffixSingle.Text == #"a - z" && CmbSuffixDouble.Text == "")
{
var p = 'a';
for (var i = 0; i <= 25; i++)
{
var keyword = TxtKeyword.Text + " " + p;
terms.Add(keyword);
p++;
//Console.WriteLine(keyword);
}
}
}

Try using these extension methods:
public static IEnumerable<string> AppendSuffix(
this string #this, string dictionary)
{
return dictionary.Select(x => #this + x);
}
public static IEnumerable<string> AppendSuffix(
this string #this, string dictionary, int levels)
{
var r = #this.AppendSuffix(dictionary);
if (levels > 1)
{
r = r.SelectMany(x => x.AppendSuffix(dictionary, levels - 1));
}
return r;
}
public static IEnumerable<string> AppendSuffix(
this IEnumerable<string> #this, string dictionary)
{
return #this.SelectMany(x => x.AppendSuffix(dictionary));
}
public static IEnumerable<string> AppendSuffix(
this IEnumerable<string> #this, string dictionary, int levels)
{
var r = #this.AppendSuffix(dictionary);
if (levels > 1)
{
r = r.SelectMany(x => x.AppendSuffix(dictionary, levels - 1));
}
return r;
}
Then call them like this:
"Hello ".AppendSuffix("abc"); // Hello a, Hello b, Hello c
"Hello ".AppendSuffix("abc", 2); // Hello aa to Hello cc
"Hello "
.AppendSuffix("abc")
.AppendSuffix("0123456789"); // Hello a0 to Hello c9

Related

If a string contains a double character change it to another string C#

I created a Person Model:
Model Person = new Model();
Person.LastName = values[0];
[LastName is a string]
I would like to replace the values [0] which is "Anna" with another string value like "Frank" if it contains a double character, in this case "if Anna contains a double character, change the value
with another string".
how to do?
Write a helper function to test for consecutive equal characters:
private static bool HasDoubleCharacter(string s)
{
char? previous = null;
foreach (char ch in s) {
if (ch == previous) {
return true;
}
previous = ch;
}
return false;
}
The you can write
Model Person = new Model();
string name = values[0];
if (HasDoubleCharacter(name)) {
name = "Frank";
}
Person.LastName = name;
You could also create a new array containing only names with no double character and use that one instead:
Model Person = new Model();
string[] names = values
.Where(v => !HasDoubleCharacter(v))
.ToArray();
if (names.Length > 0) {
Person.LastName = names[0];
}
Same idea as in MichaƂ Turczyn post - a check for double character, but implemented via regular expressions:
using System.Text.RegularExpressions;
...
public static bool HasDoubleChar(string value) =>
value != null && Regex.IsMatch(value, #"(.)\1");
pattern (.)\1 explained:
(.) - group which contains an arbitrary character
\1 - the group #1 repeated again
Note, that we have some flexibility here: (\p{L})\1 will check for double letters only, not, say, spaces; (?i)(.)\1 will compare ignoring case (Aaron will be matched) etc.
then as usual
Person.LastName = HasDoubleChar(values[0])
? "Frank"
: values[0];
This could be achieved with easy extensions funciton for string:
public static class StringExtensions
{
public static bool HasDoubleChar(this string #this)
{
ArgumentNullException.ThrowIfNull(#this);
for (int i = 1; i < #this.Length; i++)
{
if (#this[i] == #this[i - 1])
{
return true;
}
}
return false;
}
}
and then you could use it:
Person.LastName = values[0].HasDoubleChar()
? "Frank"
: values[0];
public static string Do(string source, string replacement)
{
char c = source.ToLower()[0]; // do you care about case? E.g., Aaron.
for(int i = 1; i < source.Length; i++)
{
if (source.ToLower()[i] == c)
{
return replacement;
}
}
return source;
}
public static void Main()
{
string thing = "Aaron";
thing = Do(thing, "Frank");
}

rearrange the characters of a string so that any two adjacent characters are not the same

How to rearrange the characters of a string so that any two adjacent characters are not the same? using c#
c#
Without using Hashmaps and Dictionary
I managed to find each element of the string, and the occurrence of each element.
This is what I've done so far
Using LINQ, you can gather the characters of the string, group them by duplicate characters, then pivot the groups and join then back into a string.
First, some extension methods to make Join easier:
public static class IEnumerableExt {
public static string Join(this IEnumerable<char> chars) => String.Concat(chars); // faster >= .Net Core 2.1
public static string Join(this IEnumerable<string> strings) => String.Concat(strings);
}
Then, an extension method to pivot an IEnumerable<IEnumerable<T>>:
public static class IEnumerableIEnumerableExt {
public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> src) {
var enums = src.Select(ie => ie.GetEnumerator()).ToList();
var hasMores = Enumerable.Range(0, enums.Count).Select(n => true).ToList();
for (; ; ) {
var oneGroup = new List<T>();
var hasMore = false;
for (int j1 = 0; j1 < enums.Count; ++j1) {
if (hasMores[j1]) {
hasMores[j1] = enums[j1].MoveNext();
hasMore = hasMore || hasMores[j1];
if (hasMores[j1])
oneGroup.Add(enums[j1].Current);
}
}
if (!hasMore)
break;
yield return oneGroup;
}
for (int j1 = 0; j1 < enums.Count; ++j1)
enums[j1].Dispose();
}
}
Finally, use these to solve your problem:
var s = "How to rearrange the characters of a string";
var tryAns = s.OrderBy(c => c)
.GroupBy(ch => ch)
.Pivot()
.Select(gch => gch.Join())
.Join();
var dupRE = new Regex(#"(.)\1", RegexOptions.Compiled);
var hasDups = dupRE.IsMatch(tryAns);
// tryAns will be " Hacefghinorstw aceghnorst aeort aert ar r "
// hasDups will be false
If the resulting string has two adjacent identical characters, then hasDups will be true.

How to sort on 2 distinct rules in List<string>

I need to sort a List<string> following 2 rules.
My string element will always be formatted as XXXnnnnE or XXXnnnnD where X are capitalized letters from A to Z and n are digit from 0 to 9.
I want to sort my list alphabetically, but I want E string to come before D string as shown below
DFG0001D
AWK0007E
ORK0127E
AWK0007D
DFG0001E
ORK0127D
need to be sorted as
AWK0007E
AWK0007D
DFG0001E
DFG0001D
ORK0127E
ORK0127D
How could I achieve this ?
Thanks for help
Here is snippet how you can do this with Linq OrderBy and ThenByDescending operations:
string[] arr = { "DFG0001D", "AWK0007E", "ORK0127E", "AWK0007D", "DFG0001E", "ORK0127D" };
arr = arr
.OrderBy(r => r.Substring(0, 7))
.ThenByDescending(s => s.Substring(7, 1))
.ToArray();
you can use a custom delegate and compare the 1st 3 chars and the last one:
List<string> x = new List<string>();
x.Add("DFG0001D");
x.Add("AWK0007E");
x.Add("ORK0127E");
x.Add("AWK0007D");
x.Add("DFG0001E");
x.Add("ORK0127D");
x.Sort(delegate(string c1, string c2) {
string a = c1.Substring(0, 3)+c1.Substring(c1.Length-1, 1);
string b = c2.Substring(0, 3)+c2.Substring(c2.Length-1, 1);
return (a.CompareTo(b));
});
Console.WriteLine("After sort...");
foreach (string i in x)
{
Console.WriteLine(i);
}
Fiddle example : https://dotnetfiddle.net/YAzvB4
var list = new List<string>{
"DFG0001D",
"AWK0007E",
"ORK0127E",
"AWK0007D",
"DFG0001E",
"ORK0127D"
};
list.Sort((str1, str2) => {
var eq = string.Compare(str1.Substring(0, str1.Length - 1), str2.Substring(0, str2.Length - 1));
if (eq == 0)
eq = string.Compare(str2[str2.Length - 1].ToString(), "E");
return eq;
});
foreach (var str in list)
Console.WriteLine(str);
Output:
AWK0007E
AWK0007D
DFG0001E
DFG0001D
ORK0127E
ORK0127D
just implement your own comparer like this:
class CustomStringComparer : IComparer<string>
{
private readonly IComparer<string> _baseComparer;
public CustomStringComparer(IComparer<string> baseComparer)
{
_baseComparer = baseComparer;
}
public int Compare(string x, string y)
{
// strings are completely same
if (_baseComparer.Compare(x, y) == 0)
{
return 0;
}
// strings are completely same except last char
if (_baseComparer.Compare(x.Substring(0, x.Length - 2), y.Substring(0, y.Length - 2)) == 0)
{
// if last char is E then win
return x.Last() == 'E' ? -1 : 1;
}
// defaut compare everything else
return _baseComparer.Compare(x, y);
}
}
Then you are able doing this:
static void Main(string[] args)
{
List<string> list = new List<string>()
{
"DFG0001D",
"AWK0007E",
"ORK0127E",
"AWK0007D",
"DFG0001E",
"ORK0127D"
};
list.Sort(new CustomStringComparer(StringComparer.CurrentCulture));
foreach (var item in list)
{
Console.WriteLine(item);
}
}
And output is this:
AWK0007E
AWK0007D
DFG0001E
DFG0001D
ORK0127E
ORK0127D

Query Expansion logic in C#

I have to write logic for expanding queries for solr search engine. I am using
Dictionary<string, string> dicSynon = new Dictionary<string, string>();.
Each time I will be getiing strings like "2 ln ca". In my dictionary I am having synonyms for ln and ca as lane and california. Now I need to pass solr all the combination of strings. Like this
2 ln ca
2 lane ca
2 lane california
2 ln california
Please help me to build the logic....
This is a exercise in using combinatorics and Linqs SelectMany:
First you have to writeyourself some function to give you a sequence of synonyms given a word (including the word, so "2" will result in ("2")) - let's call this 'Synonmys' - using a dictionary it can look like this:
private Dictionary<string, IEnumerable<string>> synonyms = new Dictionary<string, IEnumerable<string>>();
public IEnumerable<string> GetSynonmys(string word)
{
return synonyms.ContainsKey(word) ? synonyms[word] : new[]{word};
}
(you have to fill the Dictionary yourself...)
Having this your task is rather easy - just think on it. You have to combine every synonym of a word with all the combinations you get from doing the task on the rest of the words - that's exactly where you can use SelectMany (I only paste the rest seperated by a space - maybe you should refactor a bit) - the Algorithm yourself is your standard recursive combinations-algorithm - you will see this a lot if you know this kind of problem:
public string[] GetWords(string text)
{
return text.Split(new[]{' '}); // add more seperators if you need
}
public IEnumerable<string> GetCombinations(string[] words, int lookAt = 0)
{
if (lookAt >= words.Length) return new[]{""};
var currentWord = words[lookAt];
var synonymsForCurrentWord = GetSynonmys(currentWord);
var combinationsForRest = GetCombinations(words, lookAt + 1);
return synonymsForCurrentWord.SelectMany(synonym => combinationsForRest.Select(rest => synonym + " " + rest));
}
Here is a complete example:
class Program
{
static void Main(string[] args)
{
var test = new Synonmys(Tuple.Create("ca", "ca"),
Tuple.Create("ca", "california"),
Tuple.Create("ln", "ln"),
Tuple.Create("ln", "lane"));
foreach (var comb in test.GetCombinations("2 ln ca"))
Console.WriteLine("Combination: " + comb);
}
}
class Synonmys
{
private Dictionary<string, IEnumerable<string>> synonyms;
public Synonmys(params Tuple<string, string>[] syns )
{
synonyms = syns.GroupBy(s => s.Item1).ToDictionary(g => g.Key, g => g.Select(kvp => kvp.Item2));
}
private IEnumerable<string> GetSynonmys(string word)
{
return synonyms.ContainsKey(word) ? synonyms[word] : new[]{word};
}
private string[] GetWords(string text)
{
return text.Split(new[]{' '}); // add more seperators if you need
}
private IEnumerable<string> GetCombinations(string[] words, int lookAt = 0)
{
if (lookAt >= words.Length) return new[]{""};
var currentWord = words[lookAt];
var synonymsForCurrentWord = GetSynonmys(currentWord);
var combinationsForRest = GetCombinations(words, lookAt + 1);
return synonymsForCurrentWord.SelectMany(synonym => combinationsForRest.Select(rest => synonym + " " + rest));
}
public IEnumerable<string> GetCombinations(string text)
{
return GetCombinations(GetWords(text));
}
}
Feel free to comment if something is not crystal-clear here ;)

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