I'm trying to make a function that returns the index of the Nth occurrence of a given char in a string.
Here is my attempt:
private int IndexOfNth(string str, char c, int n)
{
int index = str.IndexOf(c) + 1;
if (index >= 0)
{
string temp = str.Substring(index, str.Length - index);
for (int j = 1; j < n; j++)
{
index = temp.IndexOf(c) + 1;
if (index < 0)
{
return -1;
}
temp = temp.Substring(index, temp.Length - index);
}
index = index + (str.Length);
}
return index;
}
This should find the first occurrence, chop off that front part of the string, find the first occurrence from the new substring, and on and on until it gets the index of the nth occurrence. However I failed to consider how the index of the final substring is going to be offset from the original actual index in the original string. How do I make this work?
Also as a side question, if I want the char to be the tab character do I pass this function '\t' or what?
Don't do that; IndexOf takes a second parameter that specifies where to start.
private static int IndexOfNth(string str, char c, int n) {
int s = -1;
for (int i = 0; i < n; i++) {
s = str.IndexOf(c, s + 1);
if (s == -1) break;
}
return s;
}
Taking all these substrings seems pretty wasteful to me. Why not just loop yourself?
private int IndexOfNth(string str, char c, int n)
{
int remaining = n;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == c)
{
remaining--;
if (remaining == 0)
{
return i;
}
}
}
return -1;
}
(I considered using IndexOf in a loop like minitech's solution, but decided it was a bit fiddly. Either's fine, of course. Both basically do the same work, only ever checking each character once. Using IndexOf may be slightly more efficient, but go for whichever you find more readable.)
Using LINQ to find the index of the 5'th a in the string aababaababa:
var str = "aababaababa";
var ch = 'a';
var n = 5;
var result = str
.Select((c, i) => new { c, i })
.Where(x => x.c == ch)
.Skip(n - 1)
.FirstOrDefault();
return result != null ? result.i : -1;
I tend to first think about how to access the collection using Linq.
// 0-based n.
char result = str
.Where(x => x == c)
.Skip(n)
.FirstOrDefault();
Then I'll unpack the linq and add the indexed iteration.
int foundCount = -1;
for(int position = 0; position < str.Length; position++)
{
char x = str[position];
if (x == c)
{
foundCount += 1;
// 0-based n
if (foundCount == n)
{
return position;
}
}
}
return -1;
Then I think about: what if this method returned all the indexes so I can query them:
public IEnumerable<int> IndexesOf(string str, char c)
{
for(int position = 0; position < str.Length; position++)
{
char x = str[position];
if (x == c)
{
yield return position;
}
}
}
Called by:
int position = IndexesOf(str, c)
.Skip(n) // 0-based n
.DefaultIfEmpty(-1)
.First();
Instead of creating a bunch of substrings, why not use the IndexOf overload that takes a starting index? This will be both easier (you won't have to adjust the final index) and more efficient (you don't have to allocate a bunch of substrings).
Not tested but something like this should work:
private int IndexOfNth(string str, char c, int n)
{
int index = -1;
while (n-- > 0)
{
index = str.IndexOf(c, index + 1);
if (index == -1) break;
}
return index;
}
Hadn't seen anyone use the CharEnumerator yet...
public Int32 getNthIndex(string str, char c, Int32 n)
{
Int32 index = 0;
Int32 count = 0;
if (str != null && str.Length > 0 && !(n < 1))
{
CharEnumerator scanner = str.GetEnumerator();
while (scanner.MoveNext())
{
if (scanner.Current == c) { count++; }
if (count == n) { break; }
index++;
}
if (count < n) { index = -1; }
}
if (count == 0) { return -1; } else { return index; }
}
Should be pretty efficient, no substrings or anything, just scan through the string you're given and keep count.
You could use the following method which will return the nth occurrence of the specified character within the designated string.
public static int IndexOfNthCharacter(string str, int n, char c) {
int index = -1;
if (!str.Contains(c.ToString()) || (str.Split(c).Length-1 < n)) {
return -1;
}
else {
for (int i = 0; i < str.Length; i++) {
if (n > 0) {
index++;
}
else {
return index;
}
if (str[i] == c) {
n--;
}
}
return index;
}
}
Note that if the character you are searching for does not exist within the string you are searching or the the occurrence number you are searching for is greater than what exists in the string then this method will return -1.
First of all, I'd make it an extension method. This way, you can skip the otherwise obligatory null check and also just call it on a string like you would do with IndexOf, IndexOfAny etc.
Then I'd make two methods of this. One to retrieve all indexes (IndexesOf, that might come handy at sometime) and the other one (IndexOfNth) uses the first function to check for the nth index:
using System;
using System.Collections.Generic; // # Necessary for IList<int>
using System.Linq; // # Necessary for IList<int>.ToArray()
/// <summary>
/// Returns all indexes of the specified <paramref name="value"/> in the current string.
/// </summary>
/// <param name="#this">The current string this method is operating on.</param>
/// <param name="value">The value to be searched.</param>
/// <returns><c>Null</c>, if <paramref name="value"/> is <c>null</c> or empty.
/// An array holding all indexes of <paramref name="value"/> in this string,
/// else.</returns>
static int[] IndexesOf(this string #this, string value)
{
// # Can't search for null or string.Empty, you can return what
// suits you best
if (string.IsNullOrEmpty(value))
return null;
// # Using a list instead of an array saves us statements to resize the
// array by ourselves
IList<int> indexes = new List<int>();
int startIndex = 0;
while (startIndex < #this.Length)
{
startIndex = #this.IndexOf(value, startIndex);
if (startIndex >= 0)
{
// # Add the found index to the result and increment it by length of value
// afterwards to keep searching AFTER the current position
indexes.Add(startIndex);
startIndex += value.Length;
}
else
{
// # Exit loop, if value does not occur in the remaining string
break;
}
}
// # Return an array to conform with other string operations.
return indexes.ToArray();
}
/// <summary>
/// Returns the indexes of the <paramref name="n"/>th occurrence of the specified
/// <paramref name="value"/> in the current string.
/// </summary>
/// <param name="#this">The current string this method is operating on.</param>
/// <param name="value">The value to be searched.</param>
/// <param name="n">The 1-based nth occurrence.</param>
/// <returns><c>-1</c>, if <paramref name="value"/> is <c>null</c> or empty -or-
/// <paramref name="n"/> is less than 1.</returns>
static int IndexOfNth(this string #this, string value, int n /* n is 1-based */)
{
// # You could throw an ArgumentException as well, if n is less than 1
if (string.IsNullOrEmpty(value) || n < 1)
return -1;
int[] indexes = #this.IndexesOf(value);
// # If there are n or more occurrences of 'value' in '#this'
// return the nth index.
if (indexes != null && indexes.Length >= n)
{
return indexes[n - 1];
}
return -1;
}
You can overload these using char value instead of string value in the signature and calling their respective counterparts passing value.ToString(). Et voilá!
Surely, these methods can be refactored, e.g. using LINQ, make IndexesOf recursive etc.
Related
I tried with this code, but it only displays whether a given string is palindrome or not. I want to extract and display all the possible palindrome substrings in the given string.
public static boolean istPalindrom(char[] word){
int i1 = 0;
int i2 = word.length - 1;
while (i2 > i1) {
if (word[i1] != word[i2]) {
return false;
}
++i1;
--i2;
}
return true;
}
Expected output:
232
12321
b12321b
ab12321ba
343
kjjk
Here is an example:
using System;
public class Program
{
private static bool istPalindrom(string word){
int i1 = 0;
int i2 = word.Length - 1;
while (i2 > i1) {
if (word[i1] != word[i2]) {
return false;
}
++i1;
--i2;
}
return true;
}
private static void FindPalindromes(string s)
{
// Assume a palindrome string is at least 2 characters
const int MinLength = 2;
if (s.Length <= MinLength)
{
return;
}
// Test all substrings by removing i first characters
for (int i = 0; i < s.Length - MinLength; i++)
{
string sub = s.Substring(i);
if (istPalindrom(sub))
{
Console.WriteLine($"Found palindrome: {sub}");
}
}
// Test all strings by the last character
FindPalindromes(s.Substring(0, s.Length - 1));
}
public static void Main()
{
FindPalindromes("ab12321bakjjkh3432");
}
}
which uses your istPalindrom method to check (but with string instead of char[]). This tests all possible substrings of the given string. There are probably more efficient ways to do this, taking advantage of a palindrome of length n must contain a palindrom of length n - 2, meaning one could find all palindromes of length 3 and 4, and then try expanding those strings.
Output:
Found palindrome: 343
Found palindrome: kjjk
Found palindrome: ab12321ba
Found palindrome: b12321b
Found palindrome: 12321
Found palindrome: 232
Palindrome initial string
public static string PalindromeString { get; set; } = "ab12321bakjjkh3432";
Actual logic to print palindrome string from given string
for (float index = 0; index < PalindromeString.Length; index += (float).5)
{
// set nearest element radius
// on both left and right side
float palindromeNearestElementRadius = index - (int)index;
// if there is need to compare indexes and if it has desired elements
// and both sides of value matches for Example (212) etc.....
while ((index + palindromeNearestElementRadius) < PalindromeString.Length
&& (index - palindromeNearestElementRadius) >= 0
&& PalindromeString[(int)(index - palindromeNearestElementRadius)]
== PalindromeString[(int)(index + palindromeNearestElementRadius)])
{
var element = PalindromeString.Substring((int)(index - palindromeNearestElementRadius),
(int)(index + palindromeNearestElementRadius + 1) -
(int)(index - palindromeNearestElementRadius));
if (element.Length != 1)
{
Console.WriteLine(element);
}
// increasing the element radius by 1
// to point towards the
// next elements for both sides to move forward our comparision
//
palindromeNearestElementRadius++;
}
Output
232
12321
b12321b
ab12321ba
jj
kjjk
343
Sample string:
A3148579
Expected result:
798514A3
I tried this code:
public static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
the actual result is 9758413A
but I want 798514A3
thanks everyone
You can try below code. This is just to give you a idea and you can update based on the test cases and requirement. Below code works fine for your input which you have mentioned. I have not considered if the length is odd. You can do your research and update logic which will help you to learn and know more.
string input = "A3148579";
Stack stack = new Stack();
int count = 0;
string output = "";
for (int i = 0; i < input.Length/2; i++)
{
stack.Push(input.Substring(count, 2));
count = count + 2;
}
while (stack.Count > 0)
{
output += stack.Pop().ToString();
}
You can split the initial string into chunks of size = 2 (e.g. with a help of Substring); note that ToCharArray() returns chars i.e. chunks of size = 1.
Let's generalize the solution: now we have size of chunks
Code:
using System.Linq;
...
public static string Reverse(string s, int size = 2) {
if (size < 1)
throw new ArgumentOutOfRangeException(nameof(size));
if (string.IsNullOrEmpty(s))
return s;
int n = s.Length / size + (s.Length % size == 0 ? 0 : 1);
return string.Concat(Enumerable
.Range(0, n)
.Select(i => i < n - 1 ? s.Substring(i * size, size) : s.Substring(i * size))
.Reverse());
}
Demo:
Console.Write(Reverse("A3148579"));
Outcome:
798514A3
C# Example: Split An Array into Multiple Smaller Arrays
Use Lambda expression to extends Array class to include a new method called Split:
public static class MyArrayExtensions
{
/// <summary>
/// Splits an array into several smaller arrays.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array to split.</param>
/// <param name="size">The size of the smaller arrays.</param>
/// <returns>An array containing smaller arrays.</returns>
public static IEnumerable<IEnumerable<T>> Split<T>(this T[] array, int size)
{
for (var i = 0; i < (float)array.Length / size; i++)
{
yield return array.Skip(i * size).Take(size);
}
}
}
Test the new array class method:
[TestMethod]
public void TestSplit2()
{
string str = "A3148579";
char[] array1 = new char[str.Length];
for (int i = 0; i < array1.Length; i++)
{
array1[i] = i;
}
// Split into smaller arrays of maximal 2 elements
IEnumerable<IEnumerable<int>> splited = array1.Split<int>(2);
int j = 0;
foreach (IEnumerable<int> s in splited){
j++;
}
log.InfoFormat("Splitted in to {0} smaller arrays.", j);
}
Finally you just need to reverse the resulted array(smaller).
I am trying to arrange an array from the small value to grow, and for some reason this function does not work (SmallToGrow), the rest is excellent. Thanks.
There are auxiliary functions that I use and are excellent facts, only the (SmallToGrow) function does not work for me and I cannot understand why. I'd love anyone who can help. Thanks
enter code here
//this check if all cells equals
public bool EverybodyAreEqual(int [] array)
{
for (int i = 0; i < array.Length - 1; i++)
if (array[i] != array[i + 1])
return false;
return true;
}
//This function changes all the values in the array that contain the -numInArray- value you entered,
// to the -numChanged- value you entered
public void ChangNumWhere(ref int [] array,int numInArray,int numChanged)
{
for (int i = 0; i < array.Length; i++)
if (array[i] == numInArray)
array[i] = numChanged;
}
//A function that returns the number of values that are not equal in the array
public int NumDifferentArray(int [] array)
{
int[] arr = new int[array.Length];
for (int i = 0; i < arr.Length; i++)
arr[i] = array[i];
bool con = true;
int contain = 0;
int index = 0;
for(int i=0; con;i++)
{
if (!arr.Contains(i))
{
contain = i;
con = false;
}
}
while(!this.EverybodyAreEqual(arr))
{
for (int i = 0; i < arr.Length; i++)
if (arr[i] != contain)
{
this.ChangNumWhere(ref arr, arr[i], contain);
index++;
}
}
return index;
}
public int HowTimesExsist(int [] array,int num)
{
int index = 0;
for(int i=0;i<array.Length;i++)
{
if (array[i] == num)
index++;
}
return index;
}
/// This function returns a minimum value as required,
/// for example if you requested 0 the smallest value is returned,
/// if 1 is returned one above it and so on,
/// if the index is greater than the length of the array the largest number is returned
public int MinBottom(int[] array, int num)
{
if (num < 0)
throw new Exception("num canot be less then 0");
int max = this.MaxArray(array);
while (num > 0)
{
int min = this.MinArray(array);
for (int i = 0; i < array.Length; i++)
if(array[i]==min)
array[i] = max;
num--;
}
return this.MinArray(array);
}
public int[] SmallToGrow(int [] array)
{
int i = 0;
int[] arr = new int[array.Length];
for (int j = 0; j < this.NumDifferentArray(array); j++)
for (int b = 0; b < this.HowTimesExsist(array, MinBottom(array, j)); i++, b++)
arr[i] = this.MinBottom(array, j);
return arr;
}
Why don't you use a list instead? They have a method attached to it that sorts it all for you.
List<int> sortInt = new List<int>() { 2, 5, 1, 50, 258, 87, 63, 52, 100, 85, 21 };
sortInt.Sort();
Returned them in numerical order with [0] being 1 and [10] being 258.
you can then turn the list to an array with sortint.ToArray();.
Edit
As dymanoid mentioned you can just use your array and just run the array.Sort() method with it. Learn something new every day.
It looks like you are in large part re-engineering some common functionality in System.Collections.Generic and System.Linq -
public bool EverybodyAreEqual(int[] array)
{
// If all items are the same,
// there should only be one distinct item in the collection
return array.Distinct().Length == 1;
}
public int NumDifferentArray(int[] array)
{
// Group the numbers in the array and
// count the number of groups with only one item
return array.GroupBy(number => number).Where(g => g.Count() == 1);
}
public int HowTimesExsist(int[] array, int num)
{
// Count the number of times a number appears in the array
return array.Count(n => n == num);
}
/// This function returns a minimum value as required,
/// for example if you requested 0 the smallest value is returned,
/// if 1 is returned one above it and so on,
/// if the index is greater than the length of the array the largest number is returned
public int MinBottom(int[] array, int num)
{
if (num < 0)
{
// Be specific about the type of exception you are throwing
throw new ArgumentOutOfRangeException(nameof(num));
}
// Sort a copy of your array
var sorted = Array.Copy(array);
Array.Sort(sorted);
// If there are any items over the specified minimum, return those
// otherwise, return the highest number in the array
// Using LastOrDefault for the maximum will return 0 if the initial array is empty
var itemsOverMinimum = sorted.Where(n => n >= num);
return itemsOverMinimum.Any() ? itemsOverMinimum.First() : sorted.LastOrDefault();
}
public int[] SmallToGrow(int[] array)
{
// Because you are returning an array, that implies that the original array should not change
// Copy the array and sort it
var copy = Array.Copy(array);
Array.Sort(copy);
return copy;
}
I saw that you mentioned that you are trying to find alternative ways to accomplish some of these things, and I want to give you some advice about that.
I think it's pretty cool that you want to challenge yourself. However, this specific functionality is part of System libraries. One of the best parts about working in C# is how much of this sort of thing is already written for you, and this functionality being added to System means that Microsoft believes these pieces are the core (pun intended) building blocks for working in .NET.
Unless your project is to specifically write a better sorting algorithm, you are not going to write this better than it is in those libraries. I've been doing this for a while, and I'm not going to be able to either.
But that doesn't mean you should stop learning. Instead, I would encourage you to look at the github source for the methods I used in my snippets above. I think that will probably be a lot more helpful than re-engineering this stuff from scratch.
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Distinct.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Grouping.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Where.cs
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Linq/src/System/Linq/Count.cs
I would like to generate a list of all possible permutations of a string containing a variable list of characters.
For example if I have the string "ABC", I would like to have a list that contains all the possible variations, like: A, B, C, AB, BC.
Thank you.
It's hard to tell exactly what you want, but based on your example output here's how to do what I think you're after in F#.
let combinations (s:string) =
let rec loop acc i =
seq {
for i in i .. (s.Length - 1) do
let acc = acc + s.[i..i]
yield acc
yield! loop acc (i + 1)
}
loop "" 0
combinations "ABC" |> Seq.toList //["A"; "AB"; "ABC"; "AC"; "B"; "BC"; "C"]
Here's a LINQ version:
Func<string, IEnumerable<string>> perm = t =>
{
Func<string, string, IEnumerable<string>> perm2 = null;
perm2 =
(t0, t1s) =>
from n in Enumerable.Range(0, t1s.Length)
let c = t1s.Substring(n, 1)
let x = t1s.Remove(n, 1)
let h = t0 + c
from r in (new [] { h, }).Concat(perm2(h, x))
select r;
return perm2("", t);
};
Use it like this:
var ps = perm("abc");
And it will perform a lazy computation.
var ps = perm("abcdefghijklmnopqrstuvwxyz").Take(2);
// Only computes two values when executed
Here will return all of the permutations (not distinct) given a string of chars. it's not fast or efficient, but it does work...
public List<string> permute(string value, string prefix = "")
{
List<string> result = new List<string>();
for (int x=0;x<value.Length;x++)
{
result.Add(prefix + value[x]);
result.AddRange(permute( value.Remove(x, 1), prefix + value[x]));
}
return result;
}
To use:
List<string> output = permute("abc");
Check out this snippet at F# Snippets
If you are looking for a permutation by index (instead of having to iterate over all the permutations) you can use a numbering system called factoradics (Source) to find them. Here is the code from the original article, with a stronger C# style (the original code is very 'C++ish') and generics.
/// <summary>
/// Permutes the specified atoms; in lexicographical order.
/// </summary>
/// <typeparam name="T">The type of elements.</typeparam>
/// <param name="atoms">The atoms.</param>
/// <param name="index">The index of the permutation to find.</param>
/// <returns>The permutation.</returns>
public static IList<T> Permute<T>(this IList<T> atoms, int index)
{
var result = new T[atoms.Count];
Permute(atoms, result, index);
return result;
}
/// <summary>
/// Permutes the specified atoms; in lexicographical order.
/// </summary>
/// <typeparam name="T">The type of elements.</typeparam>
/// <param name="atoms">The atoms.</param>
/// <param name="target">The array to place the permutation in.</param>
/// <param name="index">The index of the permutation to find.</param>
public static void Permute<T>(this IList<T> atoms, IList<T> target, int index)
{
if (atoms == null)
throw new ArgumentNullException("atoms");
if (target == null)
throw new ArgumentNullException("target");
if (target.Count < atoms.Count)
throw new ArgumentOutOfRangeException("target");
if (index < 0)
throw new ArgumentOutOfRangeException("index");
var order = atoms.Count;
// Step #1 - Find factoradic of k
var perm = new int[order];
for (var j = 1; j <= order; j++)
{
perm[order - j] = index % j;
index /= j;
}
// Step #2 - Convert factoradic[] to numeric permuatation in perm[]
var temp = new int[order];
for (var i = 0; i < order; i++)
{
temp[i] = perm[i] + 1;
perm[i] = 0;
}
perm[order - 1] = 1; // right-most value is set to 1.
for (var i = order - 2; i >= 0; i--)
{
perm[i] = temp[i];
for (var j = i + 1; j < order; j++)
{
if (perm[j] >= perm[i])
perm[j]++;
}
}
// Step #3 - map numeric permutation to string permutation
for (var i = 0; i < order; ++i)
{
target[i] = atoms[perm[i] - 1];
}
}
I have a question about iterate through the Alphabet.
I would like to have a loop that begins with "a" and ends with "z". After that, the loop begins "aa" and count to "az". after that begins with "ba" up to "bz" and so on...
Anybody know some solution?
Thanks
EDIT: I forgot that I give a char "a" to the function then the function must return b. if u give "bnc" then the function must return "bnd"
First effort, with just a-z then aa-zz
public static IEnumerable<string> GetExcelColumns()
{
for (char c = 'a'; c <= 'z'; c++)
{
yield return c.ToString();
}
char[] chars = new char[2];
for (char high = 'a'; high <= 'z'; high++)
{
chars[0] = high;
for (char low = 'a'; low <= 'z'; low++)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:
Second attempt: more flexible alphabet
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
public static IEnumerable<string> GetExcelColumns()
{
return GetExcelColumns(Alphabet);
}
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
foreach(char c in alphabet)
{
yield return c.ToString();
}
char[] chars = new char[2];
foreach(char high in alphabet)
{
chars[0] = high;
foreach(char low in alphabet)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").
Third attempt (revised further) - infinite sequence
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
int length = 0;
char[] chars = null;
int[] indexes = null;
while (true)
{
int position = length-1;
// Try to increment the least significant
// value.
while (position >= 0)
{
indexes[position]++;
if (indexes[position] == alphabet.Length)
{
for (int i=position; i < length; i++)
{
indexes[i] = 0;
chars[i] = alphabet[0];
}
position--;
}
else
{
chars[position] = alphabet[indexes[position]];
break;
}
}
// If we got all the way to the start of the array,
// we need an extra value
if (position == -1)
{
length++;
chars = new char[length];
indexes = new int[length];
for (int i=0; i < length; i++)
{
chars[i] = alphabet[0];
}
}
yield return new string(chars);
}
}
It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.
Note that if you want to stop at a certain point, you can just use LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Restarting" the iterator
To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.
Edit: Made it do exactly as the OP's latest edit wants
This is the simplest solution, and tested:
static void Main(string[] args)
{
Console.WriteLine(GetNextBase26("a"));
Console.WriteLine(GetNextBase26("bnc"));
}
private static string GetNextBase26(string a)
{
return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}
private static IEnumerable<string> Base26Sequence()
{
long i = 0L;
while (true)
yield return Base26Encode(i++);
}
private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
string returnValue = null;
do
{
returnValue = base26Chars[value % 26] + returnValue;
value /= 26;
} while (value-- != 0);
return returnValue;
}
The following populates a list with the required strings:
List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
result.Add (ch.ToString());
}
for (char i = 'a'; i <= 'z'; i++)
{
for (char j = 'a'; j <= 'z'; j++)
{
result.Add (i.ToString() + j.ToString());
}
}
I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:
static string NextColumn(string column){
char[] c = column.ToCharArray();
for(int i = c.Length - 1; i >= 0; i--){
if(char.ToUpper(c[i]++) < 'Z')
break;
c[i] -= (char)26;
if(i == 0)
return "A" + new string(c);
}
return new string(c);
}
Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.
You may also find use for these companion functions:
static string GetColumnName(int index){
StringBuilder txt = new StringBuilder();
txt.Append((char)('A' + index % 26));
//txt.Append((char)('A' + --index % 26));
while((index /= 26) > 0)
txt.Insert(0, (char)('A' + --index % 26));
return txt.ToString();
}
static int GetColumnIndex(string name){
int rtn = 0;
foreach(char c in name)
rtn = rtn * 26 + (char.ToUpper(c) - '#');
return rtn - 1;
//return rtn;
}
These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.
As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.
Here’s what I came up with.
/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (!string.IsNullOrEmpty(letter))
{
char lastLetterInString = letter[letter.Length - 1];
// if the last letter in the string is the last letter of the alphabet
if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1)
{
//replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
}
else
{
// replace the last letter in the string with the proceeding letter of the alphabet
return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
}
}
//return the first letter of the alphabet
return alphabet[0].ToString();
}
just curious , why not just
private string alphRecursive(int c) {
var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
if (c >= alphabet.Length) {
return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
} else {
return "" + alphabet[c%alphabet.Length];
}
}
This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array
q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
s = alphabet[r] + s;
q = q div 26;
r = q mod 26;
}
Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.
I gave this a go and came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Alphabetty
{
class Program
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static int cursor = 0;
static int prefixCursor;
static string prefix = string.Empty;
static bool done = false;
static void Main(string[] args)
{
string s = string.Empty;
while (s != "Done")
{
s = GetNextString();
Console.WriteLine(s);
}
Console.ReadKey();
}
static string GetNextString()
{
if (done) return "Done";
char? nextLetter = GetNextLetter(ref cursor);
if (nextLetter == null)
{
char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
if(nextPrefixLetter == null)
{
done = true;
return "Done";
}
prefix = nextPrefixLetter.Value.ToString();
nextLetter = GetNextLetter(ref cursor);
}
return prefix + nextLetter;
}
static char? GetNextLetter(ref int letterCursor)
{
if (letterCursor == alphabet.Length)
{
letterCursor = 0;
return null;
}
char c = alphabet[letterCursor];
letterCursor++;
return c;
}
}
}
Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.
I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.
That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".
So you can call it 1 of two ways..
//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample")
//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
myNextValue = IncrementAlphaNumericValue(myNextValue)
//And of course do something with this like write it out
}
(For me, I was doing something like "1AA000")
public string IncrementAlphaNumericValue(string Value)
{
//We only allow Characters a-b, A-Z, 0-9
if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
{
throw new Exception("Invalid Character: Must be a-Z or 0-9");
}
//We work with each Character so it's best to convert the string to a char array for incrementing
char[] myCharacterArray = Value.ToCharArray();
//So what we do here is step backwards through the Characters and increment the first one we can.
for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
{
//Converts the Character to it's ASCII value
Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);
//We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
{
myCharacterArray[myCharIndex]++;
//Now that we have Incremented the Character, we "reset" all the values to the right of it
for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
{
myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
if (myCharValue >= 65 && myCharValue <= 90)
{
myCharacterArray[myResetIndex] = 'A';
}
else if (myCharValue >= 97 && myCharValue <= 122)
{
myCharacterArray[myResetIndex] = 'a';
}
else if (myCharValue >= 48 && myCharValue <= 57)
{
myCharacterArray[myResetIndex] = '0';
}
}
//Now we just return an new Value
return new string(myCharacterArray);
}
}
//If we got through the Character Loop and were not able to increment anything, we retun a NULL.
return null;
}
Here's my attempt using recursion:
public static void PrintAlphabet(string alphabet, string prefix)
{
for (int i = 0; i < alphabet.Length; i++) {
Console.WriteLine(prefix + alphabet[i].ToString());
}
if (prefix.Length < alphabet.Length - 1) {
for (int i = 0; i < alphabet.Length; i++) {
PrintAlphabet(alphabet, prefix + alphabet[i]);
}
}
}
Then simply call PrintAlphabet("abcd", "");