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;.
I have an array of integers where each value will have distinct meanings.The first value means the length of permutation, the second value represent the length of initial prefix and rest of integers are single integer that make up prefix of all permutations.
For e.g. if the array has elements {5,2,1,4}
where 5 is the number of elements in the permutation array.
and 2 is the length of the integer that will makeup the first 2 elements prefix in the array permutation. 1,4 are the prefix integers i.e. length 2 in 5 element permutation combination so missing elements are 2,3,5 where 1&4 being common prefix across all permutations as below
[14235][14253][14325][14352][14523][14532] where input array is {5,2,1,4}
How to achieve this?
I have below code to get the permutation of one missing elements 2,3 & 5 but I am not getting how to program the entire the solution
static void Main(string[] args)
{
int output;
int ip1;
ip1 = Convert.ToInt32(Console.ReadLine());
int ip2_size = 0;
ip2_size = Convert.ToInt32(Console.ReadLine());
int[] ip2 = new int[ip2_size];
int ip2_item;
for (int ip2_i = 0; ip2_i < ip2_size; ip2_i++)
{
ip2_item = Convert.ToInt32(Console.ReadLine());
ip2[ip2_i] = ip2_item;
}
output = correctResult(ip1, ip2);
Console.WriteLine(output);
}
static int correctResult(int n, int[] arr)
{
int permLength = 0;
int prefLength = 0;
int result = 0;
permLength = n;
prefLength = arr.Length;
int[] permArray = new int[permLength];
int len = 0;
var missingNum = Enumerable.Range(1,
permLength).Except(arr).ToArray<int>();
if (permLength < (missingNum.Length + len))
{
result = -1;
}
else
{
for (int i = 0; i < missingNum.Length; i++)
{
permArray[prefLength + i] = missingNum[i];
}
result = permute(missingNum, 0, missingNum.Length - 1);
}
return result;
}
static int permute(int[] arry, int i, int n)
{
int j;
if (i == n)
{
int s1, s2;
s1 = s2 = 0;
for (int a = 0; a < n - 1; a++)
{
for (int b = a + 1; b < n; b++)
{
if (arry[a] > arry[b])
{
s1++;
}
}
s2 = s2 + Math.Max(0, a + 1 - arry[a]);
}
int count = 0;
if (s1 == s2)
count++;
return count;
}
else
{
int count = 0;
for (j = i; j <= n; j++)
{
swap(ref arry[i], ref arry[j]);
count += permute(arry, i + 1, n);
swap(ref arry[i], ref arry[j]);
}
return count;
}
}
static void swap(ref int a, ref int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
Try solving this with immutable types, its easier to reason about them. If, after solving the problem, you have a performance goal you haven't met then you can start trying to optimize the code.
Consider the following approach with an immutable stack that keeps track of the current permutation:
static IEnumerable<IEnumerable<int>> GetPermutations(IList<int> input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (input.Count < 2)
throw new ArgumentException("Input does not have a valid format.");
var setSize = input[0];
var prefixSize = input[1];
if (prefixSize != input.Count - 2)
throw new ArgumentException("Input does not have a valid format.");
if (input.Skip(2).Any(i => i > setSize)) //we are assuming, per example, that valid range starts at 1.
throw new ArgumentException("Input does not have a valid format.");
//Ok, we've got a valid input, interesting stuff starts here.
var prefix = input.Skip(2).ToArray();
var initialSet = Enumerable.Range(1, setSize)
.Except(prefix)
.ToArray();
foreach (var p in getPermutations(ImmutableStack<int>.Empty, initialSet))
{
yield return prefix.Concat(p);
}
IEnumerable<IEnumerable<int>> getPermutations(ImmutableStack<int> permutation, IEnumerable<int> set)
{
if (permutation.Count == setSize - prefixSize)
{
yield return permutation;
}
else
{
foreach (var i in set)
{
foreach (var p in getPermutations(permutation.Push(i), set.Except(new[] { i })))
{
yield return p;
}
}
}
}
}
And that is it, solving your problem was about 10-12 lines of real code (not considering input validation). Note that I am using some c#7 features here, but its easily translatable to previous versions of the language. Also I'd like to underline the argument validation we are doing upfront; make sure you have a valid input before trying out anything.
For ImmutableStack<T> you can use the one in System.Collections.Immutable (you have to download the NuGet package) or implement your own, its simple:
private class ImmutableStack<T>: IEnumerable<T>
{
public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
private readonly T head;
private readonly ImmutableStack<T> tail;
private ImmutableStack() { }
private ImmutableStack(T head, ImmutableStack<T> tail)
{
Debug.Assert(tail != null);
this.head = head;
this.tail = tail;
Count = tail.Count + 1;
}
public int Count { get; }
public T Peek() =>
this != Empty ? head : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Pop() =>
this != Empty ? tail : throw new InvalidOperationException("Empty stack.");
public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
public IEnumerator<T> GetEnumerator()
{
var current = this;
while (current != Empty)
{
yield return current.head;
current = current.tail;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
If you use the collections in System.Collections.Immutable, then you'll probably want to use some kind of immutable set for initalSet and set.
You can rewrite your permute method (based on this answer):
private static IEnumerable<IEnumerable<T>> Permute<T>(List<T> prefix, List<T> suffix)
{
for (var i = 0; i < suffix.Count; ++i)
{
var newPrefix = new List<T>(prefix) {suffix[i]};
var newSuffix = new List<T>(suffix.Take(i).Concat(suffix.Skip(i + 1)));
if (newSuffix.Count == 0)
{
yield return newPrefix;
continue;
}
foreach (var permutation in Permute(newPrefix, newSuffix))
yield return permutation;
}
}
And use it like this:
public static void PrintAllPermutations()
{
var input = new[] {5, 2, 1, 4};
var prefix = input.Skip(2).Take(input[1]).ToList();
var suffx = Enumerable.Range(1, input[0]).Except(prefix).ToList();
foreach (var permutation in Permute(prefix, suffx))
Console.WriteLine(string.Join(", ", permutation));
}
Reult would be:
1, 4, 2, 3, 5
1, 4, 2, 5, 3
1, 4, 3, 2, 5
1, 4, 3, 5, 2
1, 4, 5, 2, 3
1, 4, 5, 3, 2
I was given 30 minutes to complete the following task in an interview for an entry level C# developer role, the closest I could get to was to find out if the characters in both sides of the current index matched each other.
Construct an array which takes in an string and determines if at index
(i) the substring to
the left of (i) when reversed, equals to the substring to the right of
(i).
example: "racecar"
at index(3) the left substring is "rac" and when reversed equals to
the right substring "car".
return (i) if met with such condition, eslse return -1.
if string length is under 3, return 0;
if (str.Length < 3)
return -1;
for (int i = 0; i < str.Length - 1; i++)
{
if(str[i-1] == str [i+1])
return i;
}
return -1;
If i != n/2 you should return false, so just check for i==n/2:
int n = str.Length;
for (int i=0;i<=n/2;i++)
{
if (str[i] != str[n-i-1])
return -1;
}
return n/2;
I came up with this, but I really hope you were sitting in front of Visual Studio when they asked this...
using System.Linq;
class Program {
// New version: in fact, we are only looking for palindromes
// of odd length
static int FancyQuestion2(string value) {
if (value.Length % 2 == 0) {
return -1;
}
string reversed = new string(value.ToCharArray().Reverse().ToArray());
if (reversed.Equals(value, StringComparison.InvariantCultureIgnoreCase)) {
return (int)(value.Length / 2);
}
return -1;
}
static void Main(string[] args) {
int i1 = FancyQuestion2("noon"); // -1 (even length)
int i2 = FancyQuestion2("racecar"); // 3
int i3 = FancyQuestion2("WasItACatISaw"); // 6
}
}
public static int check(string str)
{
if(str.Length < 3)
return 0;
int n = str.Length;
int right = str.Length-1;
int left = 0;
while (left < right)
{
if (str[left] != str[right])
return -1;
left++;
right--;
}
return n / 2;
}
public static bool check(string s, int index)
{
if (s.Length < 3)
return false;
string left = s.Substring(0, index);
Char[] rightChars = s.Substring(index + 1).ToCharArray();
Array.Reverse(rightChars);
string right =new string (rightChars);
return left.Equals(right);
}
try this
static void Main(string[] args)
{
string theword = Console.ReadLine();
char[] arrSplit = theword.ToCharArray();
bool status = false;
for (int i = 0; i < arrSplit.Length; i++)
{
if (i < theword.Length)
{
string leftWord = theword.Substring(0, i);
char[] arrLeft = leftWord.ToCharArray();
Array.Reverse(arrLeft);
leftWord = new string(arrLeft);
string rightWord = theword.Substring(i + 1, theword.Length - (i + 1));
if (leftWord == rightWord)
{
status = true;
break;
}
}
}
Console.Write(status);
Console.ReadLine();
}
Your approach is correct, but the implementation is wrong. You need a different loop variable than i, as that contains the index of the (supposedly) center character in the string.
Also, you can't return the index from inside the loop, then you will only check one pair of character. You have to loop through the string, then check the result.
int checkPalindrome(string str, int i) {
// check that the index is at the center of the string
if (i != str.Length - i - 1) {
return -1;
}
// a variable to keep track of the state
bool cont = true;
// loop from 1 until you reach the first and last characters
for (int j = 1; cont && i - j >= 0; j++) {
// update the status
cont &= str[i - j] == str[i + j];
}
// check if the status is still true
if (cont) {
return i;
} else {
return -1;
}
}
This is the shortest I can think of:
using System;
public class Test
{
public static void Main()
{
string example = "racecar";
bool isPal = IsBothEndsPalindrome(example, 3);
Console.WriteLine(isPal);
}
static bool IsBothEndsPalindrome(string s, int i) {
while(i-- > 0) {
if(s[i] != s[s.Length - i - 1]) return false;
}
return true;
}
}
How it operates: http://ideone.com/2ae3j
Another approach, test for -1 upon return, the shortestz I can think of:
using System;
public class Test
{
public static void Main()
{
TestPal( "Michael", 3 );
TestPal( "racecar", 3 );
TestPal( "xacecar", 3 );
TestPal( "katutak", 3 );
TestPal( "able was i ere i saw elba", 7 );
TestPal( "radar", 2 );
TestPal( "radars", 2 );
// This is false, space is not ignored ;-)
TestPal( "a man a plan a canal panama", 9 );
}
static void TestPal(string s, int count) {
Console.WriteLine( "{0} : {1}", s, IsBothEndsPalindrome(s, count) );
}
static bool IsBothEndsPalindrome(string s, int count) {
while(--count >= 0 && s[count] == s[s.Length - count - 1]);
return count == -1;
}
}
Output:
Michael : False
racecar : True
xacecar : False
katutak : True
able was i ere i saw elba : True
radar : True
radars : False
a man a plan a canal panama : False
Note: The last one is False, the space is not ignored by code
Pure C, but hope the workflow helps you getting there. Thanks for sharing this.
int is_palindrome (const char str[], unsigned int index)
{
int len = strlen(str);
int result = index;
//index not valid?
if (index >= len)
return -1;
int i;
for (i = 0; ((index+i) < len && (index - i) >= 0); ++i) {
if(str[index-i] != str[index+i])
return -1;
else
continue;
}
return result;
}
I need help with creating a C# method that returns the index of the Nth occurrence of a character in a string.
For instance, the 3rd occurrence of the character 't' in the string "dtststxtu" is 5.
(Note that the string has 4 ts.)
public int GetNthIndex(string s, char t, int n)
{
int count = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == t)
{
count++;
if (count == n)
{
return i;
}
}
}
return -1;
}
That could be made a lot cleaner, and there are no checks on the input.
There is a minor bug in previous solution.
Here is some updated code:
s.TakeWhile(c => (n -= (c == t ? 1 : 0)) > 0).Count();
Here's another LINQ solution:
string input = "dtststx";
char searchChar = 't';
int occurrencePosition = 3; // third occurrence of the char
var result = input.Select((c, i) => new { Char = c, Index = i })
.Where(item => item.Char == searchChar)
.Skip(occurrencePosition - 1)
.FirstOrDefault();
if (result != null)
{
Console.WriteLine("Position {0} of '{1}' occurs at index: {2}",
occurrencePosition, searchChar, result.Index);
}
else
{
Console.WriteLine("Position {0} of '{1}' not found!",
occurrencePosition, searchChar);
}
Just for fun, here's a Regex solution. I saw some people initially used Regex to count, but when the question changed no updates were made. Here is how it can be done with Regex - again, just for fun. The traditional approach is best for simplicity.
string input = "dtststx";
char searchChar = 't';
int occurrencePosition = 3; // third occurrence of the char
Match match = Regex.Matches(input, Regex.Escape(searchChar.ToString()))
.Cast<Match>()
.Skip(occurrencePosition - 1)
.FirstOrDefault();
if (match != null)
Console.WriteLine("Index: " + match.Index);
else
Console.WriteLine("Match not found!");
Here is a recursive implementation - as an extension method, mimicing the format of the framework method(s):
public static int IndexOfNth(
this string input, string value, int startIndex, int nth)
{
if (nth < 1)
throw new NotSupportedException("Param 'nth' must be greater than 0!");
if (nth == 1)
return input.IndexOf(value, startIndex);
return input.IndexOfNth(value, input.IndexOf(value, startIndex) + 1, --nth);
}
Also, here are some (MBUnit) unit tests that might help you (to prove it is correct):
[Test]
public void TestIndexOfNthWorksForNth1()
{
const string input = "foo<br />bar<br />baz<br />";
Assert.AreEqual(3, input.IndexOfNth("<br />", 0, 1));
}
[Test]
public void TestIndexOfNthWorksForNth2()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(21, input.IndexOfNth("<br />", 0, 2));
}
[Test]
public void TestIndexOfNthWorksForNth3()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(34, input.IndexOfNth("<br />", 0, 3));
}
Update: Index of Nth occurance one-liner:
int NthOccurence(string s, char t, int n)
{
s.TakeWhile(c => n - (c == t)?1:0 > 0).Count();
}
Use these at your own risk. This looks like homework, so I left a few bugs in there for your to find:
int CountChars(string s, char t)
{
int count = 0;
foreach (char c in s)
if (s.Equals(t)) count ++;
return count;
}
.
int CountChars(string s, char t)
{
return s.Length - s.Replace(t.ToString(), "").Length;
}
.
int CountChars(string s, char t)
{
Regex r = new Regex("[\\" + t + "]");
return r.Match(s).Count;
}
ranomore correctly commented that Joel Coehoorn's one-liner doesn't work.
Here is a two-liner that does work, a string extension method that returns the 0-based index of the nth occurrence of a character, or -1 if no nth occurrence exists:
public static class StringExtensions
{
public static int NthIndexOf(this string s, char c, int n)
{
var takeCount = s.TakeWhile(x => (n -= (x == c ? 1 : 0)) > 0).Count();
return takeCount == s.Length ? -1 : takeCount;
}
}
I add another answer that run pretty fast compared to others methods
private static int IndexOfNth(string str, char c, int nth, int startPosition = 0)
{
int index = str.IndexOf(c, startPosition);
if (index >= 0 && nth > 1)
{
return IndexOfNth(str, c, nth - 1, index + 1);
}
return index;
}
Here's another, maybe simpler implementation of string IndexOfNth() with strings implementation.
Here's the string match version:
public static int IndexOfNth(this string source, string matchString,
int charInstance,
StringComparison stringComparison = StringComparison.CurrentCulture)
{
if (string.IsNullOrEmpty(source))
return -1;
int lastPos = 0;
int count = 0;
while (count < charInstance )
{
var len = source.Length - lastPos;
lastPos = source.IndexOf(matchString, lastPos,len,stringComparison);
if (lastPos == -1)
break;
count++;
if (count == charInstance)
return lastPos;
lastPos += matchString.Length;
}
return -1;
}
and the char match version:
public static int IndexOfNth(string source, char matchChar, int charInstance)
{
if (string.IsNullOrEmpty(source))
return -1;
if (charInstance < 1)
return -1;
int count = 0;
for (int i = 0; i < source.Length; i++)
{
if (source[i] == matchChar)
{
count++;
if (count == charInstance)
return i;
}
}
return -1;
}
I think for such a low level implementation you'd want to stay away from using LINQ, RegEx or recursion to reduce overhead.
Joel's answer is good (and I upvoted it). Here is a LINQ-based solution:
yourString.Where(c => c == 't').Count();
Here is a fun way to do it
int i = 0;
string s="asdasdasd";
int n = 3;
s.Where(b => (b == 'd') && (i++ == n));
return i;
public int GetNthOccurrenceOfChar(string s, char c, int occ)
{
return String.Join(c.ToString(), s.Split(new char[] { c }, StringSplitOptions.None).Take(occ)).Length;
}
string result = "i am 'bansal.vks#gmail.com'"; // string
int in1 = result.IndexOf('\''); // get the index of first quote
int in2 = result.IndexOf('\'', in1 + 1); // get the index of second
string quoted_text = result.Substring(in1 + 1, in2 - in1); // get the string between quotes
you can do this work with Regular Expressions.
string input = "dtststx";
char searching_char = 't';
int output = Regex.Matches(input, "["+ searching_char +"]")[2].Index;
best regard.
Since the built-in IndexOf function is already optimized for searching a character within a string, an even faster version would be (as extension method):
public static int NthIndexOf(this string input, char value, int n)
{
if (n <= 0) throw new ArgumentOutOfRangeException("n", n, "n is less than zero.");
int i = -1;
do
{
i = input.IndexOf(value, i + 1);
n--;
}
while (i != -1 && n > 0);
return i;
}
Or to search from the end of the string using LastIndexOf:
public static int NthLastIndexOf(this string input, char value, int n)
{
if (n <= 0) throw new ArgumentOutOfRangeException("n", n, "n is less than zero.");
int i = input.Length;
do
{
i = input.LastIndexOf(value, i - 1);
n--;
}
while (i != -1 && n > 0);
return i;
}
Searching for a string instead of a character is as simple as changing the parameter type from char to string and optionally add an overload to specify the StringComparison.
if your interested you can also create string extension methods like so:
public static int Search(this string yourString, string yourMarker, int yourInst = 1, bool caseSensitive = true)
{
//returns the placement of a string in another string
int num = 0;
int currentInst = 0;
//if optional argument, case sensitive is false convert string and marker to lowercase
if (!caseSensitive) { yourString = yourString.ToLower(); yourMarker = yourMarker.ToLower(); }
int myReturnValue = -1; //if nothing is found the returned integer is negative 1
while ((num + yourMarker.Length) <= yourString.Length)
{
string testString = yourString.Substring(num, yourMarker.Length);
if (testString == yourMarker)
{
currentInst++;
if (currentInst == yourInst)
{
myReturnValue = num;
break;
}
}
num++;
}
return myReturnValue;
}
public static int Search(this string yourString, char yourMarker, int yourInst = 1, bool caseSensitive = true)
{
//returns the placement of a string in another string
int num = 0;
int currentInst = 0;
var charArray = yourString.ToArray<char>();
int myReturnValue = -1;
if (!caseSensitive)
{
yourString = yourString.ToLower();
yourMarker = Char.ToLower(yourMarker);
}
while (num <= charArray.Length)
{
if (charArray[num] == yourMarker)
{
currentInst++;
if (currentInst == yourInst)
{
myReturnValue = num;
break;
}
}
num++;
}
return myReturnValue;
}
public static int IndexOfAny(this string str, string[] values, int startIndex, out string selectedItem)
{
int first = -1;
selectedItem = null;
foreach (string item in values)
{
int i = str.IndexOf(item, startIndex, StringComparison.OrdinalIgnoreCase);
if (i >= 0)
{
if (first > 0)
{
if (i < first)
{
first = i;
selectedItem = item;
}
}
else
{
first = i;
selectedItem = item;
}
}
}
return first;
}
Another RegEx-based solution (untested):
int NthIndexOf(string s, char t, int n) {
if(n < 0) { throw new ArgumentException(); }
if(n==1) { return s.IndexOf(t); }
if(t=="") { return 0; }
string et = RegEx.Escape(t);
string pat = "(?<="
+ Microsoft.VisualBasic.StrDup(n-1, et + #"[.\n]*") + ")"
+ et;
Match m = RegEx.Match(s, pat);
return m.Success ? m.Index : -1;
}
This should be slightly more optimal than requiring RegEx to create a Matches collection, only to discard all but one match.
public static int FindOccuranceOf(this string str,char #char, int occurance)
{
var result = str.Select((x, y) => new { Letter = x, Index = y })
.Where(letter => letter.Letter == #char).ToList();
if (occurence > result.Count || occurance <= 0)
{
throw new IndexOutOfRangeException("occurance");
}
return result[occurance-1].Index ;
}
Hi all i have created two overload methods for finding nth occurrence of char and for text with less complexity without navigating through loop ,which increase performance of your application.
public static int NthIndexOf(string text, char searchChar, int nthindex)
{
int index = -1;
try
{
var takeCount = text.TakeWhile(x => (nthindex -= (x == searchChar ? 1 : 0)) > 0).Count();
if (takeCount < text.Length) index = takeCount;
}
catch { }
return index;
}
public static int NthIndexOf(string text, string searchText, int nthindex)
{
int index = -1;
try
{
Match m = Regex.Match(text, "((" + searchText + ").*?){" + nthindex + "}");
if (m.Success) index = m.Groups[2].Captures[nthindex - 1].Index;
}
catch { }
return index;
}
Marc Cals' LINQ Extended for generic.
using System;
using System.Collections.Generic;
using System.Linq;
namespace fNns
{
public class indexer<T> where T : IEquatable<T>
{
public T t { get; set; }
public int index { get; set; }
}
public static class fN
{
public static indexer<T> findNth<T>(IEnumerable<T> tc, T t,
int occurrencePosition) where T : IEquatable<T>
{
var result = tc.Select((ti, i) => new indexer<T> { t = ti, index = i })
.Where(item => item.t.Equals(t))
.Skip(occurrencePosition - 1)
.FirstOrDefault();
return result;
}
public static indexer<T> findNthReverse<T>(IEnumerable<T> tc, T t,
int occurrencePosition) where T : IEquatable<T>
{
var result = tc.Reverse<T>().Select((ti, i) => new indexer<T> {t = ti, index = i })
.Where(item => item.t.Equals(t))
.Skip(occurrencePosition - 1)
.FirstOrDefault();
return result;
}
}
}
Some tests.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Newtonsoft.Json;
namespace FindNthNamespace.Tests
{
public class fNTests
{
[TestCase("pass", "dtststx", 't', 3, Result = "{\"t\":\"t\",\"index\":5}")]
[TestCase("pass", new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
0, 2, Result="{\"t\":0,\"index\":10}")]
public string fNMethodTest<T>(string scenario, IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T>
{
Console.WriteLine(scenario);
return JsonConvert.SerializeObject(fNns.fN.findNth<T>(tc, t, occurrencePosition)).ToString();
}
[TestCase("pass", "dtststxx", 't', 3, Result = "{\"t\":\"t\",\"index\":6}")]
[TestCase("pass", new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
0, 2, Result = "{\"t\":0,\"index\":19}")]
public string fNMethodTestReverse<T>(string scenario, IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T>
{
Console.WriteLine(scenario);
return JsonConvert.SerializeObject(fNns.fN.findNthReverse<T>(tc, t, occurrencePosition)).ToString();
}
}
}