Changing arithmetic priority in a C# program - c#

welcome
I created a program to perform basic arithmetic operations in the C# language, but I encountered some obstacles in it
I want to change the arithmetic priority in the program, meaning I want to let the program user determine the arithmetic priority.
For example:
I want addition and subtraction before multiplication and division
Or I want to prioritize addition, then multiplication, then subtraction, then division.
And so on
internal class Program
{
static void Main(string[] args)
{
string formula= "3+5*2-3/3";
var stf = new StringToFormula();
double result = stf.Eval(formula);
Console.WriteLine(result);
Console.ReadLine();
}
}
internal class StringToFormula
{
private string[] _operators = { "-", "+", "/", "*" };
private Func<double, double, double>[] _operations = {
(a1, a2) => a1 - a2,
(a1, a2) => a1 + a2,
(a1, a2) => a1 / a2,
(a1, a2) => a1 * a2
};
Dictionary<char, int> operatorPriorities = new Dictionary<char, int>()
{
{ '+', 1 },
{ '-', 1 },
{ '*', 2 },
{ '/', 2 }
};
public double Eval(string expression)
{
List<string> tokens = getTokens(expression);
Stack<double> operandStack = new Stack<double>();
Stack<string> operatorStack = new Stack<string>();
int tokenIndex = 0;
while (tokenIndex < tokens.Count)
{
string token = tokens[tokenIndex];
if (token == "(")
{
string subExpr = getSubExpression(tokens, ref tokenIndex);
operandStack.Push(Eval(subExpr));
continue;
}
if (token == ")")
{
throw new ArgumentException("Mis-matched parentheses in expression");
}
//If this is an operator
if (Array.IndexOf(_operators, token) >= 0)
{
while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek()))
{
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
operatorStack.Push(token);
}
else
{
operandStack.Push(double.Parse(token));
}
tokenIndex += 1;
}
while (operatorStack.Count > 0)
{
string op = operatorStack.Pop();
double arg2 = operandStack.Pop();
double arg1 = operandStack.Pop();
operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2));
}
return operandStack.Pop();
}
private string getSubExpression(List<string> tokens, ref int index)
{
StringBuilder subExpr = new StringBuilder();
int parenlevels = 1;
index += 1;
while (index < tokens.Count && parenlevels > 0)
{
string token = tokens[index];
if (tokens[index] == "(")
{
parenlevels += 1;
}
if (tokens[index] == ")")
{
parenlevels -= 1;
}
if (parenlevels > 0)
{
subExpr.Append(token);
}
index += 1;
}
if ((parenlevels > 0))
{
throw new ArgumentException("Mis-matched parentheses in expression");
}
return subExpr.ToString();
}
private List<string> getTokens(string expression)
{
string operators = "()*/+-";
List<string> tokens = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in expression.Replace(" ", string.Empty))
{
if (operators.IndexOf(c) >= 0)
{
if ((sb.Length > 0))
{
tokens.Add(sb.ToString());
sb.Length = 0;
}
tokens.Add(c.ToString());
}
else
{
sb.Append(c);
}
}
if ((sb.Length > 0))
{
tokens.Add(sb.ToString());
}
return tokens;
}
}
For example when addition and subtraction take priority over multiplication and division
The result of the following equation 3 + 5 * 2-3/3 is (( (3 + 5) * (2 - 3))/3) = -2.66666
I couldn't solve the problem

Related

Determine whether each character in the first string can be uniquely replaced by a character in the second string so that the two strings are equal

Give two strings of equal size. Determine whether each character in the first string can be uniquely replaced by a character in the second string so that the two strings are equal. Display also the corresponding character pairs between the two strings. The code works well now.
Example 1:
For input data:
aab
ttd
The console will display:
True
a => t
b => d
Example 2:
For input data:
tab
ttd
The console will display:
False
In the second example the answer is false because there is no unique correspondence for the character 'a': both 't' and 'd' correspond to it.
This is my code:
using System;
namespace problemeJM
{
class Program
{
static void Main(string[] args)
{
string firstPhrase = Convert.ToString(Console.ReadLine());
string secondPhrase = Convert.ToString(Console.ReadLine());
string aux1 = string.Empty, aux2 = string.Empty;
bool x = true;
for (int i = 0; i < firstPhrase.Length; i++)
{
if (!aux1.Contains(firstPhrase[i]))
{
aux1 += firstPhrase[i];
}
}
for (int i = 0; i < secondPhrase.Length; i++)
{
if (!aux2.Contains(secondPhrase[i]))
{
aux2 += secondPhrase[i];
}
}
if (aux1.Length != aux2.Length)
{
Console.WriteLine("False");
}
else
{
for (int i = 0; i < firstPhrase.Length - 2; i++)
{
for (int j = 1; j < secondPhrase.Length - 1; j++)
{
if (firstPhrase[i] == firstPhrase[j] && secondPhrase[i] == secondPhrase[j])
{
x = true;
}
else if (firstPhrase[i] != firstPhrase[j] && secondPhrase[i] != secondPhrase[j])
{
x = true;
}
else if (firstPhrase[i] == firstPhrase[j] && secondPhrase[i] != secondPhrase[j])
{
x = false;
break;
}
else if (firstPhrase[i] != firstPhrase[j] && secondPhrase[i] == secondPhrase[j])
{
x = false;
break;
}
}
}
Console.WriteLine(x);
aux1 = string.Empty;
aux2 = string.Empty;
if (x == true)
{
for (int i = 0; i < firstPhrase.Length; i++)
{
if (!aux1.Contains(firstPhrase[i]))
{
aux1 += firstPhrase[i];
}
}
for (int i = 0; i < secondPhrase.Length; i++)
{
if (!aux2.Contains(secondPhrase[i]))
{
aux2 += secondPhrase[i];
}
}
for (int i = 0; i <= aux1.Length - 1; i++)
{
for (int j = 1; j <= aux2.Length; j++)
{
if (aux1[i] == aux1[j] && aux2[i] == aux2[j])
{
Console.WriteLine(aux1[i] + " => " + aux2[i]);
break;
}
else if (aux1[i] != aux1[j] && aux2[i] != aux2[j])
{
Console.WriteLine(aux1[i] + " => " + aux2[i]);
break;
}
}
}
}
}
}
}
}
I think you should use a Dictionary<char, char> as commented. But you need to check if there's a unique mapping in both string, so from s1 to s2 and from s2 to s1:
static bool UniqueMapping(string s1, string s2)
{
int length = Math.Min(s1.Length, s2.Length);
var dict = new Dictionary<char, char>(length);
for (int i = 0; i < length; i++)
{
char c1 = s1[i];
char c2 = s2[i];
bool contained = dict.TryGetValue(c1, out char c);
if (contained && c2 != c)
{
return false;
}
dict[c1] = c2;
}
return true;
}
Here are your samples. Note that i use UniqueMapping twice(if true after 1st):
static void Main(string[] args)
{
var items = new List<string[]> { new[]{ "aab", "ttd" }, new[] { "tab", "ttd" }, new[] { "ala bala portocala", "cuc dcuc efghficuc" }, new[] { "ala bala portocala", "cuc dcuc efghijcuc" } };
foreach (string[] item in items)
{
bool result = UniqueMapping(item[0], item[1]);
if(result) result = UniqueMapping(item[1], item[0]);
Console.WriteLine($"Word 1 <{item[0]}> Word 2 <{item[1]}> UniqueMapping? {result}");
}
}
.NET Fiddle: https://dotnetfiddle.net/4DtIyH

Find permutation of one string into other string program

Trying to make an program where it just check, if permutation of string s1 exists in string s2 or not.
Created below program and it works for below test case.
Input:
s1 = "ab"
s2 = "eidballl"
Output:
True
Explanation: s2 contains one permutation of s1 (that is ba).
But this get fail when, input s2="sdfdadddbd" , s1="ab", expected as, false, but got true.
I'm trying to figure out what is missing here. Using a sliding window approach. Below my code in c#:
public bool CheckInclusion(string s1, string s2) {
var intCharArray = new int[256];
foreach(char c in s1)
{
intCharArray[c]++;
}
int start=0,end=0;
int count=s1.Length;
bool found=false;
while(end<s2.Length)
{
if (intCharArray[s2[end]]>0) { count--;}
intCharArray[s2[end]]--;
Console.WriteLine("end:" + end + " start:"+ start);
if(end-start==s1.Length) {
if (count==0) {return true;}
if (intCharArray[s2[start]]>=0)
{
count++;
}
intCharArray[s2[start]]++;
start++;
}
end++;
}
return false;
}
you need to check all characters of permutation exist in any range of [i, i + p.Length) of the string
static class StringExtensions
{
public static bool ContainsAnyPermutationOf(this string str, string p)
{
Dictionary<char, int> chars_count = p.CreateChar_CountDictionary();
for (int i = 0; i <= str.Length - p.Length; i++)
{
string subString = str.Substring(i, p.Length);
if (DictionaryMatch(chars_count, subString.CreateChar_CountDictionary()))
{
return true;
}
}
return false;
}
private static bool DictionaryMatch(Dictionary<char, int> dictionary1, Dictionary<char, int> dictionary2)
{
if (dictionary1.Count != dictionary2.Count)
{
return false;
}
foreach (var kvp in dictionary1)
{
if (!dictionary2.ContainsKey(kvp.Key))
{
return false;
}
dictionary2[kvp.Key] = dictionary2[kvp.Key] - 1;
if (dictionary2[kvp.Key] == 0)
{
dictionary2.Remove(kvp.Key);
}
}
return true;
}
private static Dictionary<char, int> CreateChar_CountDictionary(this string str)
{
Dictionary<char, int> dic = new Dictionary<char, int>();
for (int i = 0; i < str.Length; i++)
{
if (!dic.ContainsKey(str[i]))
{
dic.Add(str[i], default);
}
dic[str[i]] = dic[str[i]] + 1;
}
return dic;
}
}
usage:
static void Main(string[] args)
{
Console.WriteLine("sdfdadddbd".ContainsAnyPermutationOf("ab"));
}
I guess the question is similar to LeetCode 567. These are simple, efficient, low-complexity accepted solutions:
C#
class Solution {
public bool CheckInclusion(string s1, string s2) {
int lengthS1 = s1.Length;
int lengthS2 = s2.Length;
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++)
countmap[s1[i] - 97]++;
int[] bCount = new int[26];
for (int i = 0; i < lengthS2; i++) {
bCount[s2[i] - 97]++;
if (i >= (lengthS1 - 1)) {
if (allZero(countmap, bCount))
return true;
bCount[s2[i - (lengthS1 - 1)] - 97]--;
}
}
return false;
}
private bool allZero(int[] s1, int[] s2) {
for (int i = 0; i < 26; i++) {
if (s1[i] != s2[i])
return false;
}
return true;
}
}
Java
class Solution {
public boolean checkInclusion(String s1, String s2) {
int lengthS1 = s1.length();
int lengthS2 = s2.length();
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++) {
countmap[s1.charAt(i) - 97]++;
countmap[s2.charAt(i) - 97]--;
}
if (allZero(countmap))
return true;
for (int i = lengthS1; i < lengthS2; i++) {
countmap[s2.charAt(i) - 97]--;
countmap[s2.charAt(i - lengthS1) - 97]++;
if (allZero(countmap))
return true;
}
return false;
}
private boolean allZero(int[] count) {
for (int i = 0; i < 26; i++)
if (count[i] != 0)
return false;
return true;
}
}
Python
class Solution:
def checkInclusion(self, s1, s2):
count_map_s1 = collections.Counter(s1)
count_map_s2 = collections.Counter(s2[:len(s1)])
for i in range(len(s1), len(s2)):
if count_map_s1 == count_map_s2:
return True
count_map_s2[s2[i]] += 1
count_map_s2[s2[i - len(s1)]] -= 1
if count_map_s2[s2[i - len(s1)]] == 0:
del(count_map_s2[s2[i - len(s1)]])
return count_map_s2 == count_map_a
Reference
The codes are explained in the following links:
LeetCode 567 Solution
LeetCode 567 Discussion Board
These two answers are also useful to look into:
Link 1
Link 2
private static bool CheckPermutationInclusion(string s1, string s2)
{
return Enumerable.Range(0, s2.Length - s1.Length)
.Select(i => s2.Substring(i, s1.Length))
.Any(x => x.All(y => s1.Contains(y)));
}
Description:
Enumerable.Range(Int32, Int32) Method: Generates a sequence of integral numbers within a specified range.
Enumerable.Select Method: Projects each element of a sequence into a new form.
Enumerable.All Method: Determines whether all elements of a sequence satisfy a condition.
Enumerable.Any Method: Determines whether any element of a sequence exists or satisfies a condition.
Do not forget using System.Linq;.

Array list is not being sorted properly when it contains string

I'm trying to sort a lists of alphanumeric values , in other words a list that contains numbers and strings
Example : BOB10, BOT20, ETC...
List<Object> myList = _items.OrderBy(x => x.FirstName).ToList();
_items= new List<Object>(myList);
But still the output is : BOT20 , BOB10
what is wrong?
First :
Try the alphanumeric algorithm approach ,
First implement the algorithm in a new class, than do this :
List<Object> yourList = new List < Object >(thePreviousList.OrderBy(x => x.FirstName, new AlphanumComparatorFast()).ToList())
As it was explained here :
http://www.dotnetperls.com/alphanumeric-sorting
Implement the algorithm AlphanumComparatorFast by creating a new class , than just call it
Edited :
The alpha algo below :
Public class AlphanumComparatorFast : IComparer
{
public int Compare(object x, object y)
{
string s1 = x as string;
if (s1 == null)
{
return 0;
}
string s2 = y as string;
if (s2 == null)
{
return 0;
}
int len1 = s1.Length;
int len2 = s2.Length;
int marker1 = 0;
int marker2 = 0;
// Walk through two the strings with two markers.
while (marker1 < len1 && marker2 < len2)
{
char ch1 = s1[marker1];
char ch2 = s2[marker2];
// Some buffers we can build up characters in for each chunk.
char[] space1 = new char[len1];
int loc1 = 0;
char[] space2 = new char[len2];
int loc2 = 0;
// Walk through all following characters that are digits or
// characters in BOTH strings starting at the appropriate marker.
// Collect char arrays.
do
{
space1[loc1++] = ch1;
marker1++;
if (marker1 < len1)
{
ch1 = s1[marker1];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
do
{
space2[loc2++] = ch2;
marker2++;
if (marker2 < len2)
{
ch2 = s2[marker2];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
// If we have collected numbers, compare them numerically.
// Otherwise, if we have strings, compare them alphabetically.
string str1 = new string(space1);
string str2 = new string(space2);
int result;
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
{
int thisNumericChunk = int.Parse(str1);
int thatNumericChunk = int.Parse(str2);
result = thisNumericChunk.CompareTo(thatNumericChunk);
}
else
{
result = str1.CompareTo(str2);
}
if (result != 0)
{
return result;
}
}
return len1 - len2;
}
}
Why not use List.Sort() instead of OrderBy?
using System;
using System.Collections.Generic;
namespace Test {
static class Program {
static void Main() {
List<string> list = new List<string>() {"BOT20", "BOB10", "BUG40", "BAG90"};
list.Sort();
foreach(var el in list) {
Console.Write(el + ">");
}
}
}
}
Outputs: BAG90>BOB10>BOT20>BUG40>

Merged String Checker (custom rules)

Write an algorithm to check if a given string, s, can be formed from two other strings, part1 and part2.
The restriction is that the characters in part1 and part2 are in the same order as in s.
Example:
'codewars' is a merge from 'cdw' and 'oears':
s: c o d e w a r s = codewars
part1: c d w = cdw
part2: o e a r s = oears
But in the test cases, it's not so easy to make it work..
The rules says they have to be the same length and in same order but with random test cases they are put in random order aswell..
So the rules conflict with the rules so how can I make it work??
Test cases that follow the rules:
[Test]
public void SadPath2()
{
Assert.IsFalse(StringMerger.isMerge("codewars", "code", "wasr"), "Codewars can't be created from code and wasr");
}
SadPath2 == false;
[Test]
public void SadPath1()
{
Assert.IsFalse(StringMerger.isMerge("codewars", "cod", "wars"), "Codewars are not codwars");
}
SadPath1 == false;
[Test]
public void HappyPath2()
{
Assert.IsTrue(StringMerger.isMerge("codewars", "cdwr", "oeas"), "codewars can be created from cdwr and oeas");
}
HappyPath2 == true;
[Test]
public void HappyPath1()
{
Assert.IsTrue(StringMerger.isMerge("codewars", "code", "wars"), "codewars can be created from code and wars");
}
HappyPath1 == true;
Some random tests that might not follow the rules completely:
[Test]
public void RandomTest()
{
Assert.IsTrue(StringMerger.isMerge("[W`meSnw(R1qaLLqc[=]=UAvTa_3%", "W`mnwqaLL]=va%", "[eS(R1qc[=UAT_3"), "'[W`meSnw(R1qaLLqc[=]=UAvTa_3%' is a merge of 'W`mnwqaLL]=va%' and '[eS(R1qc[=UAT_3'");
}
RandomTest == true;
[Test]
public void RandomTest2()
{
Assert.IsTrue(StringMerger.isMerge("]ftUNn7-XoX4AZ3i1+", "U7oX4A1+", "]ftNn-XZ3i"), "']ftUNn7-XoX4AZ3i1+' is a merge of 'U7oX4A1+' and ']ftNn-XZ3i");
}
RandomTest2 == true;
First example on my class where it can successfully run the all the tests Except SadPath2:
public class StringMerger
{
public static bool isMerge(string s, string part1, string part2)
{
int num = 0;
string txt1 = "";
Console.WriteLine("S - " + s + " - P1 - " + part1 + " - P2 - " + part2);
#region Sorting
foreach (var itm in s)
{
if (part1.Contains(itm.ToString()))
num++;
else if (part2.Contains(itm.ToString()))
num++;
}
#endregion
if (num == s.Length && num == (part1.Length + part2.Length))
return true;
return false;
}
}
Second example where it can run all except for the random tests:
public class StringMerger
{
public static bool isMerge(string s, string part1, string part2)
{
int num = 0;
int P1 = 0;
int P2 = 0;
bool p2 = false;
string txt1 = "";
#region Sorting
foreach (var itm in s)
{
if (part1.Contains(itm.ToString()))
num++;
else if (part2.Contains(itm.ToString()))
num++;
try
{
if (p2 == false)
{
txt1 = txt1 + GetLetterP1(part1, itm.ToString(), P1);
P1++;
p2 = true;
}
else
{
txt1 = txt1 + GetLetterP2(part2, itm.ToString(), P2);
P2++;
p2 = false;
}
}
catch { }
}
#endregion
if (num == s.Length && num == (part1.Length + part2.Length))
{
if (s.Contains(part1 + part2))
return true;
else if (txt1 == s)
return true;
}
return false;
}
static string GetLetterP1(string p1, string letter, int n)
{
string itm = "";
if (p1.Contains(letter))
itm = p1[n].ToString();
return itm;
}
static string GetLetterP2(string p2, string letter, int n)
{
string itm = "";
if (p2.Contains(letter))
itm = p2[n].ToString();
return itm;
}
}
Results with Kvam answer: (With the latest fixes)
Results with Max Answer: (With the latest fixes)
Results with codersl Answer: (With the latest fixes)
I think this should cover the requirements, although you might want to rewrite it to avoid string creation all around.
public bool IsMatch(string target, string part1, string part2)
{
if (target.Length != part1.Length + part2.Length)
{
return false;
}
if (target == "")
{
return true;
}
if (part1.Length > 0 && target[0] == part1[0])
{
if (IsMatch(target.Substring(1), part1.Substring(1), part2.Substring(0)))
{
return true;
}
}
if (part2.Length > 0 && target[0] == part2[0])
{
if (IsMatch(target.Substring(1), part1.Substring(0), part2.Substring(1)))
{
return true;
}
}
return false;
}
Here my 2 cents
public bool IsMerge(string target, string part1, string part2)
{
if (String.IsNullOrEmpty(target))
{
throw new ArgumentNullException("target");
}
if (String.IsNullOrEmpty(part1))
{
throw new ArgumentNullException("part1");
}
if (String.IsNullOrEmpty(part2))
{
throw new ArgumentNullException("part2");
}
if (target.Length == (part1.Length + part2.Length))
{
return this.IsPart(target, part1) && this.IsPart(target, part2);
}
return false;
}
private bool IsPart(string target, string part)
{
int idx = -1;
int lastIdx = 0;
for (int i = 0; i < part.Length; i++)
{
idx = (target.IndexOf(part[i], lastIdx));
if (!(idx > -1))
{
return false;
}
lastIdx = idx;
}
return true;
}
My 2 cents
public static void Main()
{
Console.WriteLine(Check("codewars", "code", "wasr")); //false
Console.WriteLine(Check("codewars", "cod", "wars")); //false
Console.WriteLine(Check("codewars", "cdwr", "oeas"));
Console.WriteLine(Check("codewars", "code", "wars"));
Console.WriteLine(Check("[W`meSnw(R1qaLLqc[=]=UAvTa_3%", "W`mnwqaLL]=va%", "[eS(R1qc[=UAT_3"));
Console.WriteLine(Check("]ftUNn7-XoX4AZ3i1+", "U7oX4A1+", "]ftNn-XZ3i"));
Console.WriteLine(Check("acab", "ab", "ac"));
Console.WriteLine(Check("b]aDw- !oKJnOJ", "b]aDwoKJ", "- !nOJ"));
Console.WriteLine(Check("codewars", "codewarss", "")); //false
Console.WriteLine(Check("codewars", "", "")); //false
Console.WriteLine(Check("codewars", "codewars", null));
Console.WriteLine(Check("Bananas from Bahamas", "Bahas", "Bananas from am"));
}
private static bool Check(string s, string part1, string part2)
{
if (part1 == null)
part1 = "";
if (part2 == null)
part2 = "";
var part1Index = 0;
var part2Index = 0;
var bothMatch = "";
foreach(var c in s)
{
// handle both strings matching
if (part1Index < part1.Length && part2Index < part2.Length && c == part1[part1Index] && c == part2[part2Index])
{
bothMatch += c;
part1Index++;
part2Index++;
continue;
}
if (bothMatch.Length > 0 && c == part1[part1Index])
{
// part2 doesn't match anymore so roll back its index
part2Index -= bothMatch.Length;
bothMatch = "";
}
else if (bothMatch.Length > 0 && c == part2[part2Index])
{
// part1 doesn't match anymore so roll back its index
part1Index -= bothMatch.Length;
bothMatch = "";
}
// handle one string matching
if (part1Index < part1.Length && c == part1[part1Index])
{
//Console.WriteLine("c={0}, p1={1}", c, part1[part1Index]);
part1Index++;
continue;
}
if (part2Index < part2.Length && c == part2[part2Index])
{
//Console.WriteLine("c={0}, p2={1}", c, part2[part2Index]);
part2Index++;
continue;
}
//Console.WriteLine("c={0}, p1={1}, p2={2}, both={3}", c, part1[part1Index], part2[part2Index], bothMatch);
return false;
}
return (part1Index == part1.Length) && (part2Index == part2.Length);
}

Finding all positions of substring in a larger string in C#

I have a large string I need to parse, and I need to find all the instances of extract"(me,i-have lots. of]punctuation, and store the index of each to a list.
So say this piece of string was in the beginning and middle of the larger string, both of them would be found, and their indexes would be added to the List. and the List would contain 0 and the other index whatever it would be.
I've been playing around, and the string.IndexOf does almost what I'm looking for, and I've written some code - but it's not working and I've been unable to figure out exactly what is wrong:
List<int> inst = new List<int>();
int index = 0;
while (index < source.LastIndexOf("extract\"(me,i-have lots. of]punctuation", 0) + 39)
{
int src = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
inst.Add(src);
index = src + 40;
}
inst = The list
source = The large string
Any better ideas?
Here's an example extension method for it:
public static List<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
}
}
If you put this into a static class and import the namespace with using, it appears as a method on any string, and you can just do:
List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");
For more information on extension methods, http://msdn.microsoft.com/en-us/library/bb383977.aspx
Also the same using an iterator:
public static IEnumerable<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
break;
yield return index;
}
}
Why don't you use the built in RegEx class:
public static IEnumerable<int> GetAllIndexes(this string source, string matchString)
{
matchString = Regex.Escape(matchString);
foreach (Match match in Regex.Matches(source, matchString))
{
yield return match.Index;
}
}
If you do need to reuse the expression then compile it and cache it somewhere. Change the matchString param to a Regex matchExpression in another overload for the reuse case.
using LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
Polished version + case ignoring support:
public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false)
{
if (string.IsNullOrWhiteSpace(str) ||
string.IsNullOrWhiteSpace(substr))
{
throw new ArgumentException("String or substring is not specified.");
}
var indexes = new List<int>();
int index = 0;
while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)
{
indexes.Add(index++);
}
return indexes.ToArray();
}
It could be done in efficient time complexity using KMP algorithm in O(N + M) where N is the length of text and M is the length of the pattern.
This is the implementation and usage:
static class StringExtensions
{
public static IEnumerable<int> AllIndicesOf(this string text, string pattern)
{
if (string.IsNullOrEmpty(pattern))
{
throw new ArgumentNullException(nameof(pattern));
}
return Kmp(text, pattern);
}
private static IEnumerable<int> Kmp(string text, string pattern)
{
int M = pattern.Length;
int N = text.Length;
int[] lps = LongestPrefixSuffix(pattern);
int i = 0, j = 0;
while (i < N)
{
if (pattern[j] == text[i])
{
j++;
i++;
}
if (j == M)
{
yield return i - j;
j = lps[j - 1];
}
else if (i < N && pattern[j] != text[i])
{
if (j != 0)
{
j = lps[j - 1];
}
else
{
i++;
}
}
}
}
private static int[] LongestPrefixSuffix(string pattern)
{
int[] lps = new int[pattern.Length];
int length = 0;
int i = 1;
while (i < pattern.Length)
{
if (pattern[i] == pattern[length])
{
length++;
lps[i] = length;
i++;
}
else
{
if (length != 0)
{
length = lps[length - 1];
}
else
{
lps[i] = length;
i++;
}
}
}
return lps;
}
and this is an example of how to use it:
static void Main(string[] args)
{
string text = "this is a test";
string pattern = "is";
foreach (var index in text.AllIndicesOf(pattern))
{
Console.WriteLine(index); // 2 5
}
}
Without Regex, using string comparison type:
string search = "123aa456AA789bb9991AACAA";
string pattern = "AA";
Enumerable.Range(0, search.Length)
.Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
.Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length),StringComparison.OrdinalIgnoreCase))
.Select(searchbit => searchbit.Index)
This returns {3,8,19,22}. Empty pattern would match all positions.
For multiple patterns:
string search = "123aa456AA789bb9991AACAA";
string[] patterns = new string[] { "aa", "99" };
patterns.SelectMany(pattern => Enumerable.Range(0, search.Length)
.Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
.Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length), StringComparison.OrdinalIgnoreCase))
.Select(searchbit => searchbit.Index))
This returns {3, 8, 19, 22, 15, 16}
I noticed that at least two proposed solutions don't handle overlapping search hits. I didn't check the one marked with the green checkmark. Here is one that handles overlapping search hits:
public static List<int> GetPositions(this string source, string searchString)
{
List<int> ret = new List<int>();
int len = searchString.Length;
int start = -1;
while (true)
{
start = source.IndexOf(searchString, start +1);
if (start == -1)
{
break;
}
else
{
ret.Add(start);
}
}
return ret;
}
public List<int> GetPositions(string source, string searchString)
{
List<int> ret = new List<int>();
int len = searchString.Length;
int start = -len;
while (true)
{
start = source.IndexOf(searchString, start + len);
if (start == -1)
{
break;
}
else
{
ret.Add(start);
}
}
return ret;
}
Call it like this:
List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob");
// list will contain 0, 22, 26
Hi nice answer by #Matti Virkkunen
public static List<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
index--;
}
}
But this covers tests cases like AOOAOOA
where substring
are AOOA and AOOA
Output 0 and 3
#csam is correct in theory, although his code will not complie and can be refractored to
public static IEnumerable<int> IndexOfAll(this string sourceString, string matchString)
{
matchString = Regex.Escape(matchString);
return from Match match in Regex.Matches(sourceString, matchString) select match.Index;
}
public static Dictionary<string, IEnumerable<int>> GetWordsPositions(this string input, string[] Susbtrings)
{
Dictionary<string, IEnumerable<int>> WordsPositions = new Dictionary<string, IEnumerable<int>>();
IEnumerable<int> IndexOfAll = null;
foreach (string st in Susbtrings)
{
IndexOfAll = Regex.Matches(input, st).Cast<Match>().Select(m => m.Index);
WordsPositions.Add(st, IndexOfAll);
}
return WordsPositions;
}
Based on the code I've used for finding multiple instances of a string within a larger string, your code would look like:
List<int> inst = new List<int>();
int index = 0;
while (index >=0)
{
index = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
inst.Add(index);
index++;
}
I found this example and incorporated it into a function:
public static int solution1(int A, int B)
{
// Check if A and B are in [0...999,999,999]
if ( (A >= 0 && A <= 999999999) && (B >= 0 && B <= 999999999))
{
if (A == 0 && B == 0)
{
return 0;
}
// Make sure A < B
if (A < B)
{
// Convert A and B to strings
string a = A.ToString();
string b = B.ToString();
int index = 0;
// See if A is a substring of B
if (b.Contains(a))
{
// Find index where A is
if (b.IndexOf(a) != -1)
{
while ((index = b.IndexOf(a, index)) != -1)
{
Console.WriteLine(A + " found at position " + index);
index++;
}
Console.ReadLine();
return b.IndexOf(a);
}
else
return -1;
}
else
{
Console.WriteLine(A + " is not in " + B + ".");
Console.ReadLine();
return -1;
}
}
else
{
Console.WriteLine(A + " must be less than " + B + ".");
// Console.ReadLine();
return -1;
}
}
else
{
Console.WriteLine("A or B is out of range.");
//Console.ReadLine();
return -1;
}
}
static void Main(string[] args)
{
int A = 53, B = 1953786;
int C = 78, D = 195378678;
int E = 57, F = 153786;
solution1(A, B);
solution1(C, D);
solution1(E, F);
Console.WriteLine();
}
Returns:
53 found at position 2
78 found at position 4
78 found at position 7
57 is not in 153786
How is this alternative implementation?
public static class MyExtensions
{
public static int HowMany(this string str, char needle)
{
int counter = 0;
int nextIndex = 0;
for (; nextIndex != -1; )
{
nextIndex = str.IndexOf(needle, nextIndex);
if (nextIndex != -1)
{
counter++;
//step over to the next char
nextIndex++;
}
}
return counter;
}
}
you can use linq to select and enumerate all elements, then find by any string:
I've created a class:
class Pontos
{
//index on string
public int Pos { get; set; }
//caractere
public string Caractere { get; set; }
}
And use like this:
int count = 0;
var pontos = texto.Select(y => new Pontos { Pos = count++, Caractere = y.ToString() }).Where(x=>x.Caractere == ".").ToList();
then:
input string:
output list:
PS: SeForNumero is another field of my class, I need this for my own purposes, but is not necessary to this use.

Categories