I need a piece of code that increments end of string in "[]" brackets, but I got headache with that.
Thing is, if name "test" exists in given collection, algorithm should return test_[0], if both exists then "test_[1]" etc. That works so far. But when I tried to pass as currentName value "test_[something]" algorithm creates something like test_[0]_[0], test_[0]_[1] instead of test_[somenthing+someNumber]. Does anyone know the way to change this behavior?
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
if (existingNames.Any(n => n.Equals(currentName)))
{
do
{
if (!currentName.EndsWith($"({iteration})"))
{
currentName = $"{currentName}_[{++iteration}]";
}
}
while (existingNames.Any(n => n.Equals(currentName)));
}
return currentName;
}
EDIT :
The best solution so far is that(I can bet that I've seen it here, but someone had to delete)
public static void Main()
{
var currentOriginal = "test";
var existingNamesOriginal = new[] { "test", "test_[2]", "test_[3]" };
string outputOriginal = GetDistinctNameFromSO(currentOriginal, existingNamesOriginal);
Console.WriteLine("original : " + outputOriginal);
Console.ReadLine();
}
protected static string GetDistinctNameFromSO(string currentName,
IEnumerable<string> existingNames)
{
if (null == currentName)
throw new ArgumentNullException(nameof(currentName));
else if (null == existingNames)
throw new ArgumentNullException(nameof(existingNames));
string pattern = $#"^{Regex.Escape(currentName)}(?:_\[(?<Number>[0-9]+)\])?$";
Regex regex = new Regex(pattern);
var next = existingNames
.Select(item => regex.Match(item))
.Where(match => match.Success)
.Select(match => string.IsNullOrEmpty(match.Groups["Number"].Value)
? 1
: int.Parse(match.Groups["Number"].Value))
.DefaultIfEmpty()
.Max() + 1;
if (next == 1)
return currentName; // No existingNames - return currentName
else
return $"{currentName}_[{next}]";
}
For given "test" string it returns "test_[4]" which is excellent, but if given string is let's say "test_[2]" it should also return "test_[4]"(string with given pattern with first free number), but it returns "test_[2]_[2]" instead.
I will try answer with minimal adjustments to your code:
Use square brackets to check if name exists
Use a local variable to prevent adding [0] over and over
increment iteration on every do/while loop
if the result, should never be "test", exclude it from the existing results
The result looks like (not tested, but this should get you on your way):
// test test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
// Use a different variable this will prevent you from adding [0] again and again
var result = currentName;
if (existingNames.Where(s => s != currentName).Any(n => n.Equals(result)))
{
do
{
// Use square brackets
if (!result .EndsWith($"[{iteration}]"))
{
result = $"{currentName}_[{iteration}]";
}
iteration++; // Increment with every step
}
while (existingNames.Any(n => n.Equals(result)));
}
return result;
}
Here's a simpler rewrite:
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
var name = currentName;
while(existingNames.Contains(name))
{
name = currentName + "_[" + (iteration++) + "]";
}
return name;
}
Tests:
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[2]", "test_[3]"}).Dump();//Out: test_[1]
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[1]", "test_[2]", "test_[3]"}).Dump();//Out: test_[4]
GetDistinctName2("test", new List<string> {}).Dump();//Out: test
Your description of your problem and your code and completely different. Here will increment a number inside the square brackets without appending additional text.
The change from the initial code addresses a problem mentioned in the question about including text inside the square brackets with a number. Below you can replace something with other text.
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
int iteration = 0;
string nextName = currentName;
while (existingNames.Contains(nextName))
{
nextName = $"{currentName}_[something{iteration}]";
iteration++;
}
return nextName;
}
C# interactive shell example:
> GetDistinctName2("test", new List<string>() { "test", "test_[something0]", "test_[something1]"})
"test_[something2]"
Related
I have list like this:
List<string> myList = new List<string>()
{
"AS2258B43C014AI9954803",
"AS2258B43C014AI9954603",
"AS2258B43C014AI9954703",
"AS2258B43C014AI9954503",
"AS2258B43C014AI9954403",
"AS2258B43C014AI9954203",
"AS2258B43C014AI9954303",
"AS2258B43C014AI9954103",
};
I want to output something format is sameString+diffString0\diffString1\diffString2.... like this "AS2258B43C014AI9954803\603\703\503\403\203\303\103"
what should I do?
You can create a method which returns you the difference between to strings:
private static string GetDiff (string s1, string s2)
{
int i;
for(i = 0; i < Math.Min(s1.Length,s2.Length); i++)
{
if(s1[i] != s2[i])
{
break;
}
}
return s2.Substring(i);
}
This method iterats until the first character which is different and returns the remaining characters of the second string.
With that method, you can obtain your result with the LINQ query:
string first = myList[0];
string result = first + "/" + string.Join("/", myList.Skip(1).Select(x => GetDiff(first,x)));
Online demo: https://dotnetfiddle.net/TPkhmz
Alphanumeric sorting using LINQ
Create static method for pads
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
then call it
var result = myList.OrderBy(x => PadNumbers(x));
after that you can find the difference
The simplest solution is to create a function like this :
public static string Output(List<String> ListString)
{
string sameString = ListString.First().Substring(0, 18);
string output = sameString;
foreach (var item in ListString)
{
output += item.Substring(19);
output += "\\";
}
return output.Substring(0, output.Length - 1);
}
I need to search a string and see if it contains "<addnum(x)>"
I have used .contains on the other words that i searched for and the easiest way i could think for is you somehow could make exception for numbers or do you need to use another code for that?
My code this far.
public List<string> arguments = new List<string>();
public void Custom_naming(string name_code)
{
arguments.Add("Changing the name to " + name_code); // Sets the new name.
if( name_code.Contains("<addnum>") )
{
Add_number();
}
if (name_code.Contains("<addnum(x)>"))
{// X = any number.
}
}
private void Add_number()
{
arguments.Add("Replaces all <addnum> with a number");
}
private void Add_number(int zeros)
{
arguments.Add("Replaces all <addnumxx> with a number with lentgh of");
}
You probably need to use a regular expression:
var match = Regex.Match(name_code, #"<addnum(?:\((\d+)\))?>");
if (match.Success)
{
int zeros;
if (int.TryParse(match.Groups[1].Value, out zeros))
{
Add_number(zeros);
}
else
{
Add_number();
}
}
This will return invoke the appropriate Add_number method if name_code contains <addnum> or anything like <addnum(123)>.
If there could possibly be more than one such in name_code, e.g. <addnum(1)><addnum(2)>, you'll want to use a loop to analyze each match, like this:
var matches = Regex.Matches(name_code, #"<addnum(?:\((\d+)\))?>");
foreach(var match in matches)
{
int zeros;
if (int.TryParse(match.Groups[1].Value, out zeros))
{
Add_number(zeros);
}
else
{
Add_number();
}
}
Use regular expression:
string s = "Foo <addnum(8)> bar.";
var contains = Regex.IsMatch(s, #"<addnum\(\d+\)>");
If you want also extract number:
string s = "Foo <addnum(42)> bar.";
var match = Regex.Match(s, #"<addnum\((\d+)\)>");
if (match.Success)
{
// assume you have valid integer number
var number = Int32.Parse(match.Groups[1].Value);
}
I need to take a sentence in that is all on one line with no spaces and each new word has a captial letter EX. "StopAndSmellTheRoses" and then convert it to "Stop and smell the roses" This is my function that I have but I keep getting an argument out of range error on the insert method. Thanks for any help in advance.
private void FixSentence()
{
// String to hold our sentence in trim at same time
string sentence = txtSentence.Text.Trim();
// loop through the string
for (int i = 0; i < sentence.Length; i++)
{
if (char.IsUpper(sentence, i) & sentence[i] != 0)
{
// Change to lowercase
char.ToLower(sentence[i]);
// Insert space behind the character
// This is where I get my error
sentence = sentence.Insert(i-1, " ");
}
}
// Show our Fixed Sentence
lblFixed.Text = "";
lblFixed.Text = "Fixed: " + sentence;
}
The best way to build up a String in this manner is to use a StringBuilder instance.
var sentence = txtSentence.Text.Trim();
var builder = new StringBuilder();
foreach (var cur in sentence) {
if (Char.IsUpper(cur) && builder.Length != 0) {
builder.Append(' ');
}
builder.Append(cur);
}
// Show our Fixed Sentence
lblFixed.Text = "";
lblFixed.Text = "Fixed: " + builder.ToString();
Using the Insert method creates a new string instance every time resulting in a lot of needlessly allocated values. The StringBuilder though won't actually allocate a String until you call the ToString method.
You can't modify the sentence variable in the loop that is going through it.
Instead, you need to have a second string variable that you append all of the found words.
Here is the answer
var finalstr = Regex.Replace(
"StopAndSmellTheRoses",
"(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])|(?<=[^0-9])(?<x>[0-9])(?=.)",
me => " " + me.Value.ToLower()
);
will output
Stop and smell the roses
Another version:
public static class StringExtensions
{
public static string FixSentence(this string instance)
{
char[] capitals = Enumerable.Range(65, 26).Select(x => (char)x).ToArray();
string[] words = instance.Split(capitals);
string result = string.Join(' ', words);
return char.ToUpper(result[0]) + result.Substring(1).ToLower();
}
}
I'm trying to implement a simple search function. I have a string array which contains all words which was typed in from the user to search. And I have another string which contains data like User Name, content... So what I want to do is to check is Name contains any of the elements in the search or String array. Right now I have a loop which checks one word at a time and concatenates the result in an IEnumerable.
Does anyone know a faster way of doing this search? Like String.ContainsAny(Search[])
Try this:
Search.Any(p => name.Contains(p))
using System.Linq;
string[] searchItems = ...
string input = "This is the input text";
// Check whether at least one match found
bool matchFound = input.Any(w => input.Contains(w));
// Count all matches
int matchesCount = input.Where(w => input.Contains(w))
.Count();
string[] searchItems = ...;
string[] userNames = ...;
var matches = userNames.Intersect(searchItems);
You can find more about the intersect method here
you can do like this...
return array.Any(s => s.Equals(myString))
or try like this....
string stringToCheck = "text1";
string[] stringArray = { "text1", "testtest", "test1test2", "test2text1" };
foreach (string x in stringArray)
{
if (x.Contains(stringToCheck))
{
// Process...
}
}
or Something like this
string stringToCheck = "text1text2text3";
string[] stringArray = new string[] { "text1" };
if (Array.Exists<string>(stringArray, (Predicate<string>)delegate(string s) {
return stringToCheck.IndexOf(s, StringComparison.OrdinalIgnoreCase) > -1; })) {
Console.WriteLine("Found!");
}
Two solutions to this problem for example:
Solution 1
private void findDateColumn() {
string stringToCheck = "date";
int stringToCheckIndex = -1;
string elementInArray = "Not Defined or Not Found";
if (Array.Exists<string> (headers, (Predicate<string>) delegate (string s)
{
stringToCheckIndex = s.IndexOf (stringToCheck,StringComparison.OrdinalIgnoreCase);
elementInArray = s;
return stringToCheckIndex > -1;
}))
{
dateColTitle.Text = elementInArray; //a textbox to show the output
}
}
Solution 2
I'm using #Lev answer, which seems simpler and shorter plus giving the same result:
private void setDateColumnTitle ()
{
dateColTitle.Text = "Not Defined or Not Found";
var match = headers.FirstOrDefault(c => c.IndexOf("date", StringComparison.OrdinalIgnoreCase) > -1);
if (match!=null)
dateColTitle.Text = match;
}
I have a small project where I have an input sentence where it is possible for the user to specify variations:
The {small|big} car is {red|blue}
Above is a sample sentence i want to split into 4 sentences, like this:
The small car is red
The big car is red
The small car is blue
The big car is blue
I can't seem to wrap my mind around the problem. Maybe someone can helt me pls.
Edit
Here is my initial code
Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline);
MatchCollection collection = regex.Matches(richTextBox1.Text);
string data = richTextBox1.Text;
//build amount of variations
foreach (Match match in collection)
{
string[] alternatives = match.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string alternative in alternatives)
{
//here i get problems
}
}
It sounds like you need a dynamic cartesian function for this. Eric Lippert's blog post written in response to Generating all Possible Combinations.
Firstly, we need to parse the input string:
Regex ex = new Regex(#"(?<=\{)(?<words>\w+(\|\w+)*)(?=\})");
var sentence = "The {small|big} car is {red|blue}";
then the input string should be modified to be used in string.Format-like functions:
int matchCount = 0;
var pattern = ex.Replace(sentence, me =>
{
return (matchCount++).ToString();
});
// pattern now contains "The {0} car is {1}"
then we need to find all the matches and to apply Eric's excellent CartesianProduct extension method:
var set = ex.Matches(sentence)
.Cast<Match>()
.Select(m =>
m.Groups["words"].Value
.Split('|')
).CartesianProduct();
foreach (var item in set)
{
Console.WriteLine(pattern, item.ToArray());
}
this will produce:
The small car is red
The small car is blue
The big car is red
The big car is blue
and, finally, the CartesianProduct method (taken from here):
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] {item}));
}
private void ExpandString( List<string> result, string text )
{
var start = text.IndexOf('{');
var end = text.IndexOf('}');
if (start >= 0 && end > start)
{
var head = text.Substring(0, start);
var list = text.Substring(start + 1, end - start - 1).Split('|');
var tail = text.Substring(end + 1);
foreach (var item in list)
ExpandString(result, head + item + tail);
}
else
result.Add(text);
}
Use like:
var result = new List<string>();
ExpandString(result, "The {small|big} car is {red|blue}");
If you don't know the number of variations, recursion is your friend:
static public IEnumerable<string> permute(string template)
{
List<string> options;
string before;
string after;
if (FindFirstOptionList(template, out options, out before, out after))
{
foreach (string option in options)
{
foreach (string permutation in permute(before + option + after))
{
yield return permutation;
}
}
}
else
{
yield return template;
}
}
static public bool FindFirstOptionList(string template, out List<string> options, out string before, out string after)
{
before = string.Empty;
after = string.Empty;
options = new List<string>(0);
if (template.IndexOf('{') == -1)
{
return false;
}
before = template.Substring(0, template.IndexOf('{'));
template = template.Substring(template.IndexOf('{') + 1);
if (template.IndexOf('}') == -1)
{
return false;
}
after = template.Substring(template.IndexOf('}') + 1);
options = template.Substring(0, template.IndexOf('}')).Split('|').ToList();
return true;
}
use is similar to danbystrom's solution, except this one returns an IEnumerable instead of manipulating one of the calling parameters. Beware syntax errors, etc
static void main()
{
foreach(string permutation in permute("The {small|big} car is {red|blue}"))
{
Console.WriteLine(permutation);
}
}
I would propose to split the input text into an ordered list of static and dynamic parts. Each dynamic part itself contains a list that stores its values and an index that represents the currently selected value. This index is intially set to zero.
To print out all possible combinations you at first have to implement a method that prints the complete list using the currently set indices of the dynamic parts. For the first call all indices will be set to zero.
Now you can increment the index of the first dynamic part and print the complete list. This will give you the first variation. Repeat this until you printed all possible values of the remaining dynamic parts.
Consider nesting iterative loops. Something like...
foreach(string s in someStringSet)
{
foreach(string t in someOtherStringSet)
{
// do something with s and t
}
}
Perhaps you are looking for this:
Edited version
static void Main(string[] args)
{
var thisstring = "The {Small|Big} car is {Red|Blue}";
string FirstString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1);
string[] FirstPossibility = FirstString.Replace("{", "").Replace("}", "").Split('|');
thisstring = thisstring.Replace(FirstString, "[0]");
string SecondString = thisstring.Substring(thisstring.IndexOf("{"), (thisstring.IndexOf("}") - thisstring.IndexOf("{")) + 1);
string[] SecondPosibility = SecondString.Replace("{", "").Replace("}", "").Split('|');
thisstring = thisstring.Replace(SecondString, "{1}").Replace("[0]", "{0}");
foreach (string tempFirst in FirstPossibility)
{
foreach (string tempSecond in SecondPosibility)
{
Console.WriteLine(string.Format(thisstring, tempFirst, tempSecond));
}
}
Console.Read();
}
Something like this should work:
private void Do()
{
string str = "The {small|big} car is {red|blue}";
Regex regex = new Regex("{(.*?)}", RegexOptions.Singleline);
int i = 0;
var strWithPlaceHolders = regex.Replace(str, m => "{" + (i++).ToString() + "}");
var collection = regex.Matches(str);
var alternatives = collection.OfType<Match>().Select(m => m.Value.Split(new char[] { '|', '{', '}' }, StringSplitOptions.RemoveEmptyEntries));
var replacers = GetReplacers(alternatives);
var combinations = new List<string>();
foreach (var replacer in replacers)
{
combinations.Add(string.Format(strWithPlaceHolders, replacer));
}
}
private IEnumerable<object[]> GetReplacers(IEnumerable<string[]> alternatives)
{
return GetAllPossibilities(0, alternatives.ToList());
}
private IEnumerable<object[]> GetAllPossibilities(int level, List<string[]> list)
{
if (level == list.Count - 1)
{
foreach (var elem in list[level])
yield return new[] { elem };
}
else
{
foreach (var elem in list[level])
{
var thisElemAsArray = new object[] { elem };
foreach (var subPossibilities in GetAllPossibilities(level + 1, list))
yield return thisElemAsArray.Concat(subPossibilities).ToArray();
}
}
yield break;
}
string color = SomeMethodToGetColor();
string size = SomeMethodToGetSize();
string sentence = string.Format("The {0} car is {1}", size, color);