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", "");
Related
The assignment is:
Given two arrays of strings determine whether corresponding elements contain a common substring
My code is (the method is given, I should fill it in):
public static void commonSubstring(List<string> a, List<string> b) {
string[] listA = a.ToArray();
string[] listB = b.ToArray();
bool contains = false;
for(int i = 0; i < listA.Length; i++)
{
foreach(char c in listA[i])
{
foreach (char d in listB[i]) {
if (c == d) {
contains = true;
break;
}
}
if (contains) { break; }
}
if (contains == true) {
Console.WriteLine("YES");
contains = false;
} else {
Console.WriteLine("NO");
}
}
}
It gets through most test cases, but in some it says that it takes too long (above 3 seconds) to run, so when there are large inputs. Does anyone have any idea how I can optimize this code to make it faster so that it takes less than 3 seconds to calculate with large inputs? So basically it prints a YES if a[i] and b[i] have a character in common and NO if they don't.
There is no escaping the fact that something needs to happen for every pair of listA[i], listB[i], that's not the issue. But take a good look at these nested loops:
foreach(char c in listA[i])
{
foreach (char d in listB[i]) {
if (c == d) {
contains = true;
break;
}
}
if (contains) { break; }
}
You have already discovered that we really only need to find a letter that is in both string, and then we have a common substring of length 1 (there may be a longer common substring, but it is irrelevant for this problem, as we only need to know whether it exists - you should not use a "longest common substring" algorithm, that's complete overkill). It was done by comparing every combination of characters. However, there is an alternative:
Make a HashSet with the characters from string A. For every character in string B, check whether it is in that HashSet.
The number of operations goes from the products of the lengths of the string, to the sum of the length of the strings.
So basically it prints a YES if a[i] and b[i] have a character in
common and NO if they don't.
you can optimize it by omitting the nested loop
public static void commonSubstring(List<string> a, List<string> b)
{
string[] listA = a.ToArray();
string[] listB = b.ToArray();
for (int i = 0; i < listA.Length; i++)
{
if (HaveCharInCommon(listA[i], listB[i]))
{
Console.WriteLine("YES");
}
else
{
Console.WriteLine("NO");
}
}
}
private static bool HaveCharInCommon(string a, string b)
{
var set = new HashSet<char>(a);
foreach (var ch in b)
{
if (set.Contains(ch))
{
return true;
}
}
return false;
}
Here is a O(n*log n) version of finding out if the strings have characters (substrings) in common:
Input: s1 s2
let ss1 = sort s1 (O(N log N)
let ss2 = sort s2 (O(N log N)
let l1 = length s1 (O(1) in C#, O(N) in C...)
let l2 = length s2
let i1 = 0, i2 = 0
while (i1 < l1 and i2 < l2)
{
if ss1[i1] == ss2[i2]
then return true
if ss1[i1] < ss2[i2]
then i1++, continue
if ss1[i1] > ss2[i2]
then i2++, continue
}
return false
The total complexity is O(N log N) (the sorting complexity).
I don't have C# on my system, so I apologize I have to give you an implementation
in another language instead.
(defun common-sub-string-p (s1 s2)
(let ((s1-sorted (sort s1 #'char-lessp))
(s2-sorted (sort s2 #'char-lessp))
(l1 (length s1))
(l2 (length s2)))
(labels ((compute (i1 i2)
(if (and (< i1 l1) (< i2 l2))
(let ((c1 (aref s1-sorted i1))
(c2 (aref s2-sorted i2)))
(cond
((eql c1 c2) t)
((char-lessp c1 c2) (compute (1+ i1) i2))
((char-lessp c2 c1) (compute i1 (1+ i2)))))
nil)))
(compute 0 0))))
There are plenty more ways to do this. For example, you could create 2 bit sets, use the characters of the strings as indices and then with 1 bit set for each of the 2 strings, test if they have a common subset.
If the strings are restricted to ascii encoding (0..127), those bit sets could be an array of 16 bytes (or 2 uint64), where each bit in the bytes represents the existence of a respective character.
With that, you have to loop over each character in the strings (O(N)), then do a bitwise and of the 2 resulting bit sets and if that is not zero, they have common sub strings.
Hence, the best you can get is probably O(N) for ascii strings.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int common_chars(const char* s1, const char *s2) {
uint64_t bitset1[2] = {0,0};
uint64_t bitset2[2] = {0,0};
size_t l1,l2;
l1 = strlen(s1);
l2 = strlen(s2);
for(size_t i = 0; i < l1; ++i) {
char c = s1[i];
if (c < 64) {
bitset1[0] |= 1 << c;
} else {
bitset1[1] |= 1 << (c-64);
}
}
for(size_t i = 0; i < l2; ++i) {
char c = s2[i];
if (c < 64) {
bitset2[0] |= 1 << c;
} else {
bitset2[1] |= 1 << (c-64);
}
}
if ( ((bitset1[0] & bitset2[0]) == 0)
&& ((bitset1[1] & bitset2[1]) == 0)) {
return 0;
}
return 1;
}
int main(int argc, const char* argv[]) {
if (argc >= 3) {
printf ("%s <-> %s : %s\n", argv[1],argv[2],
(common_chars(argv[1],argv[2])? "true" : "false"));
} else {
puts("you need to give 2 strings as command line arguments.");
}
return 0;
}
I'm not a pro at C#. But the mainly problem is the nested loop. The time complexity of Three level nested loop with be O(n^3).
public class Program{
public static void Main()
{
string[] listA = {"apple", "banana", "orange", "test"};
string[] listB = {"NOD", "train", "warship"};
bool contains = false;
//For preventing Array out of bound
int length = (listA.Length > listB.Length) ? listA.Length : listB.Length;
for(int i = 0; i < length; i++){
string longer = "";
string shorter = "";
//Find the shorter string for minimizing the looping time.
if(listA[i].Length > listB[i].Length) {
longer = listA[i];
shorter = listB[i];
} else {
shorter = listA[i];
longer = listB[i];
}
foreach(char a in shorter){
if(longer.Contains(a.ToString())) {
contains = true;
break;
}
}
if (contains) {
Console.WriteLine("YES");
} else {
Console.WriteLine("NO");
}
contains = false;
}
}}
guys! I have this situation: Given a string and two more characters X and Y. Move all X characters to the beginning of the string and all Y characters to the end of the string. The order of the other characters in the string remains unchanged.
I wrote two function MoveCharsLeft and MoveCharsRight to move X to the left and Y to the right, but there is an error System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' on this line of code char toReplace = splitText[charToCheck]; and I don't know how to handle it, in order to solve the exercise.
Can, you guys, help me with that, how should be the functions?
static void Main()
{
string text = Console.ReadLine();
char[] splitText = text.ToCharArray();
string firstLetter = Console.ReadLine();
char[] firstChar = firstLetter.ToCharArray();
string secondLetter = Console.ReadLine();
char[] secondChar = secondLetter.ToCharArray();
char one = firstChar[0];
char two = secondChar[0];
Console.WriteLine(CheckChars(splitText, one, two));
Console.ReadLine();
}
static char[] CheckChars(char[] splitText, char one, char two)
{
for (char letter = 'a'; letter <= 'z'; letter++)
{
if (Array.IndexOf(splitText, one) > -1)
{
MoveCharsLeft(splitText, one);
}
if (Array.IndexOf(splitText, two) > -1)
{
MoveCharsRight(splitText, two);
}
}
return splitText;
}
static void MoveCharsLeft(char[] splitText, char charToCheck)
{
char toReplace = splitText[charToCheck];
char currentLetter = splitText[0];
for (int i = 0; i <= charToCheck; i++)
{
char temporary = splitText[i];
splitText[i] = currentLetter;
currentLetter = temporary;
}
splitText[0] = toReplace;
}
static void MoveCharsRight(char[] splitText, char charToCheck)
{
char toReplace = splitText[charToCheck];
char currentLetter = splitText[-1];
for (int i = 0; i <= charToCheck; i++)
{
char temporary = splitText[i];
splitText[i] = currentLetter;
currentLetter = temporary;
}
splitText[-1] = toReplace;
}
You're not checking your boundaries. I would say CheckChars method is redundant and in MoveCharsLeft and MoveCharsRight you're not checking if you're still inside of splitText.
Here's how I would implement MoveCharsLeft, I hope it'll guide you in the right direction.
char[] MoveCharactersLeft(char[] text, char character) {
var lowerCharacter = char.ToLower(character);
var left = new List<char>();
var right = new List<char>();
foreach (var letter in text) {
if (char.ToLower(letter) == lowerCharacter) {
left.Add(letter);
continue;
}
right.Add(letter);
}
left.AddRange(right);
return left.ToArray();
}
And here's MoveCharactersRight:
char[] MoveCharactersRight(char[] text, char character) {
var lowerCharacter = char.ToLower(character);
var left = new List<char>();
var right = new List<char>();
foreach (var letter in text) {
if (char.ToLower(letter) == lowerCharacter) {
right.Add(letter);
continue;
}
left.Add(letter);
}
left.AddRange(right);
return left.ToArray();
}
Now that you have both you simply call MoveCharsLeft and then the MoveCharactersRight on the result of MoveCharsLeft.
You can swap them in place, although it requires a lot of copying. Here's a function to move a character from one spot to another in an array. You can find several examples of this on the web and SO.
public static void Move(char[] buffer, int from, int too)
{
if (from == too)
return;
char temp = buffer[from];
if (too < from)
{
Array.Copy(buffer, too, buffer, too + 1, from - too);
}
else
{
Array.Copy(buffer, from + 1, buffer, from, too - from);
}
buffer[too] = temp;
}
Then you just have to iterate through the array testing the characters, testing them and moving them to the right spot. Here's a function to do that:
public static void ArrangeChars(char[] buffer, char left, char right)
{
int leftIndex = 0;
int rightIndex = buffer.Length - 1;
int i = 0;
while(i <= rightIndex)
{
char ch = buffer[i];
if (ch == left && i > leftIndex)
Move(buffer, i, leftIndex++);
else if (ch == right && i < rightIndex)
Move(buffer, i, rightIndex--);
else
++i;
}
}
Call it like so:
static void Main(string[] _)
{
char[] data = "test me and move".ToCharArray();
Console.WriteLine(new string(data));
ArrangeChars(data, 'e', 't');
Console.WriteLine("Move 'e' to start, move 't' to end");
Console.WriteLine(new string(data));
}
The usual caveats apply - this has not been well tested and if you use it, you should check all the edge cases.
I am currently working on an assignment where I need to write a small program that will take a generic string and should output how many possible anagrams that could be generated from the string.
The string that is the input can be up to 100 chars long and could include both lowercase and uppercase, in this case both lowercase and uppercase are considered distinct. The output should only be how many possible combinations, so I don't need to output the actual anagrams.The maximum timelimit is 1 second per string.
I have tried a number of diffrent ways of doing this, but one conclusion is that this should be solvable using some type of mathemathical algorithm.
The latest code I have tried with is this:
static void Main(string[] args)
{
string line;
while ((line = Console.ReadLine()) != null)
{
var uniqueStringArr = removeDuplicates(line);
Console.WriteLine(countDistinctPermutations(new string(uniqueStringArr)));
}
}
private static char[] removeDuplicates(string line)
{
var list = line.ToList();
return list.Distinct().ToArray();
}
static int MAX_CHAR = 100;
// Utility function to find factorial of n.
static int factorial(int n)
{
int fact = 1;
for (int i = 2; i <= n; i++)
fact = fact * i;
return fact;
}
// Returns count of distinct permutations
// of str.
static int countDistinctPermutations(String str)
{
int length = str.Length;
int[] freq = new int[MAX_CHAR];
// finding frequency of all the lower case
// alphabet and storing them in array of
// integer
for (int i = 0; i < length; i++)
if (str[i] >= 'a')
freq[str[i] - 'a']++;
// finding factorial of number of appearances
// and multiplying them since they are
// repeating alphabets
int fact = 1;
for (int i = 0; i < MAX_CHAR; i++)
fact = fact * factorial(freq[i]);
// finding factorial of size of string and
// dividing it by factorial found after
// multiplying
return factorial(length) / fact;
}
The thing is that this code does not give the correct answer for all my testcases.
The following sample data was provided for me :
Input string | Number of possible anagrams
at | 2
ordeals | 5040
abcdefghijklmnopqrstuvwxyz | 403291461126605635584000000
abcdefghijklmabcdefghijklm | 49229914688306352000000
abcdABCDabcd | 29937600
My code fixes the first two examples, but I get completly diffrent numbers for the other 3.
Is there anyone who can help me with this problem because I am running out of ideas ?
/Andreas
static BigInteger Factorial(long x)
{
return x <= 1 ? 1 : x * Factorial(x-1);
}
private static BigInteger NumberOfDistinctPermutationOf(string str)
{
BigInteger dividend = Factorial(str.Length);
foreach (char chr in str)
{
dividend /= Factorial(str.Count(c => c == chr));
str = str.Replace(chr.ToString(), string.Empty);
}
return dividend;
}
Description:
BigInteger Struct: Represents an arbitrarily large signed integer.
Enumerable.Count Method: Returns a number that represents how many elements in the specified sequence satisfy a condition.
String.Replace(String, String) Method: Returns a new string in which all occurrences of a specified string in the current instance are replaced with another specified string.
GetNumberOfDistinctPermutation Method: Divides factorial of the length of the string by factorial of the number of occurrences of the char and then removes all occurrences of the char, for each char in the string.
static void Main(string[] args)
{
string line;
while ((line = Console.ReadLine()) != null)
{
Console.WriteLine($"{line} -> {countDistinctPermutations(line)}");
}
}
static BigInteger factorial(int n)
{
double fact = 1;
for (int i = 2; i <= n; i++)
fact = fact * i;
return fact;
}
static BigInteger countDistinctPermutations(String str)
{
// get a collection of {letter,occurences}
var duplicates = Array.GroupBy(p => p).Select(x => new { x.Key, count = x.Count() }).Where(x => x.count > 1);
BigInteger result = factorial(str.Length);
// foreach letter where occurence > 1 divide total permutations by the permutations for the occurence value (occurrence!)
foreach (var d in duplicates)
{
result /= factorial(d.count);
}
return result;
}
I only write code for a week so it's not that pretty but it works 100%.
static void Main(string[] args)
{
string inputData = Console.ReadLine();
Console.WriteLine(Solution(inputData));
}
static char[] convert(string text) // converting string to char[]
{
char[] newString = new char[text.Length];
for (int i = 0; i < text.Length; i++)
{
newString[i] = text[i];
}
return newString;
}
static double CalculateFctorial(double number) // calc. factorial
{
double factorial = 1;
for (int i = 1; i <= number; i++)
factorial *= i;
return factorial;
}
static int CountOcc(string text, char zet) // counting occurrences
{
int count = 0;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == zet)
{
count++;
}
}
return count;
}
static double Solution(string text) // the soluton, counting occurences of
// each char in string and each factorial
{
double net = 0;
double sol = 1;
char[] newText = convert(text);
for (int i = 0; i <= newText.Length; i++)
{
if (text.Length > 0)
{
net = CountOcc(text, newText[i]);
sol = sol * CalculateFctorial(net);
if (newText[i] == text[0])
{ text = text.Trim(text[0]); }
}
}
double solution = CalculateFctorial(newText.Length) / sol;
return solution;
}
Say we have the following strings that we pass as parameters to the function below:
string sString = "S104";
string sString2 = "AS105";
string sString3 = "ASRVT106";
I want to be able to extract the numbers from the string to place them in an int variable. Is there a quicker and/or more efficient way of removing the letters from the strings than the following code?: (*These strings will be populated dynamically at runtime - they are not assigned values at construction.)
Code:
public GetID(string sCustomTag = null)
{
m_sCustomTag = sCustomTag;
try {
m_lID = Convert.ToInt32(m_sCustomTag); }
catch{
try{
int iSubIndex = 0;
char[] subString = sCustomTag.ToCharArray();
//ITERATE THROUGH THE CHAR ARRAY
for (int i = 0; i < subString.Count(); i++)
{
for (int j = 0; j < 10; j++)
{
if (subString[i] == j)
{
iSubIndex = i;
goto createID;
}
}
}
createID: m_lID = Convert.ToInt32(m_sCustomTag.Substring(iSubIndex));
}
//IF NONE OF THAT WORKS...
catch(Exception e)
{
m_lID = 00000;
throw e;
}
}
}
}
I've done things like this before, but I'm not sure if there's a more efficient way to do it. If it was just going to be a single letter at the beginning, I could just set the subStringIndex to 1 every time, but the users can essentially put in whatever they want. Generally, they will be formatted to a LETTER-then-NUMBER format, but if they don't, or they want to put in multiple letters like sString2 or sString3, then I need to be able to compensate for that. Furthermore, if the user puts in some whacked-out, non-traditional format like string sString 4 = S51A24;, is there a way to just remove any and all letters from the string?
I've looked about, and can't find anything on MSDN or Google. Any help or links to it are greatly appreciated!
You can use a regular expression. It's not necessarily faster, but it's more concise.
string sString = "S104";
string sString2 = "AS105";
string sString3 = "ASRVT106";
var re = new Regex(#"\d+");
Console.WriteLine(re.Match(sString).Value); // 104
Console.WriteLine(re.Match(sString2).Value); // 105
Console.WriteLine(re.Match(sString3).Value); // 106
You can use a Regex, but it's probably faster to just do:
public int ExtractInteger(string str)
{
var sb = new StringBuilder();
for (int i = 0; i < str.Length; i++)
if(Char.IsDigit(str[i])) sb.Append(str[i]);
return int.Parse(sb.ToString());
}
You can simplify further with some LINQ at the expense of a small performance penalty:
public int ExtractInteger(string str)
{
return int.Parse(new String(str.Where(c=>Char.IsDigit(c)).ToArray()));
}
Now, if you only want to parse the first sequence of consecutive digits, do this instead:
public int ExtractInteger(string str)
{
return int.Parse(new String(str.SkipWhile(c=>!Char.IsDigit(c)).TakeWhile(c=>Char.IsDigit(c)).ToArray()));
}
Fastest is to parse the string without removing anything:
var s = "S51A24";
int m_lID = 0;
for (int i = 0; i < s.Length; i++)
{
int d = s[i] - '0';
if ((uint)d < 10)
m_lID = m_lID * 10 + d;
}
Debug.Print(m_lID + ""); // 5124
string removeLetters(string s)
{
for (int i = 0; i < s.Length; i++)
{
char c = s[i];
if (IsEnglishLetter(c))
{
s = s.Remove(i, 1);
}
}
return s;
}
bool IsEnglishLetter(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
While you asked "what's the fastest way to remove characters..." what you really appear to be asking is "how do I create an integer by extracting only the digits from the string"?
Going with this assumption, your first call to Convert.ToInt32 will be slow for the case where you have other than digits because of the exception throwing.
Let's try another approach. Let's think about each of the cases.
The string always starts with a series of digits (e.g. 123ABC => 123)
The string always ends with a series of digits (e.g. ABC123 => 123)
A string has a series of contiguous digits in the middle (e.g. AB123C ==> 123)
The digits are possibly noncontiguous (e.g. A77C12 => 7712)
Case 4 is the "safest" assumption (after all, it is a superset of Case 1, 2 and 3. So, we need an algorithm for that. As a bonus I'll provide algorithms specialized to the other cases.
The Main Algorithm, All Cases
Using in-place unsafe iteration of the characters of the string, which uses fixed, we can extract digits and convert them to a single number without the data copy in ToCharArray(). We can also avoid the allocations of, say, a StringBuilder implementation and a possibly slow regex solution.
NOTE: This is valid C# code though it's using pointers. It does look like C++, but I assure you it's C#.
public static unsafe int GetNumberForwardFullScan(string s)
{
int value = 0;
fixed (char* pString = s)
{
var pChar = pString;
for (int i = 0; i != s.Length; i++, pChar++)
{
// this just means if the char is not between 0-9, we exit the loop (i.e. stop calculating the integer)
if (*pChar < '0' || *pChar > '9')
continue;
// running recalculation of the integer
value = value * 10 + *pChar - '0';
}
}
return value;
}
Running this against any of the inputs: "AS106RVT", "ASRVT106", "106ASRVT", or "1AS0RVT6" results in pulling out 1, 0, 6 and calculating on each digit as
0*10 + 1 == 1
1*10 + 0 == 10
10*10 + 6 == 106
Case 1 Only Algorithm (Digits at Start of String)
This algorithm is identical to the one above, but instead of continue we can break as soon as we reach a non-digit. This would be much faster if we can assume all the inputs start with digits and the strings are long.
Case 2 Only Algorithm (Digits at End of String)
This is almost the same as Case 1 Only except you have to
iterate from the end of the string to the beginning (aka backwards) stopping on the first non-digit
change the calculation to sum up powers of ten.
Both of those are a bit tricky, so here's what that looks like
public static unsafe int GetNumberBackward(string s)
{
int value = 0;
fixed (char* pString = s)
{
char* pChar = pString + s.Length - 1;
for (int i = 0; i != -1; i++, pChar--)
{
if (*pChar < '0' || *pChar > '9')
break;
value = (*pChar - '0') * (int)Math.Pow(10, i) + value;
}
}
return value;
}
So each of the iteration of the calculation looks like
6*100 + 0 == 6
0*101 + 6 == 6
1*102 + 6 == 106
While I used Math.Pow in these examples, you can find integer only versions that might be faster.
Cases 1-3 Only (i.e. All Digits Contiguous Somewhere in the String
This algorithm says to
Scan all non-digits
Then scan only digits
First non-digit after that, stop
It would look like
public static unsafe int GetContiguousDigits(string s)
{
int value = 0;
fixed (char* pString = s)
{
var pChar = pString;
// skip non-digits
int i = 0;
for (; i != s.Length; i++, pChar++)
if (*pChar >= '0' && *pChar <= '9')
break;
for (; i != s.Length; i++, pChar++)
{
if (*pChar < '0' || *pChar > '9')
break;
value = value * 10 + *pChar - '0';
}
}
return value;
}
Instead of looping through each character to see if it's the one you want then adding the index your on to a list like so:
var foundIndexes = new List<int>();
for (int i = 0; i < myStr.Length; i++)
{
if (myStr[i] == 'a')
foundIndexes.Add(i);
}
You can use String.IndexOf, see example below:
string s = "abcabcabcabcabc";
var foundIndexes = new List<int>();
long t1 = DateTime.Now.Ticks;
for (int i = s.IndexOf('a'); i > -1; i = s.IndexOf('a', i + 1))
{
// for loop end when i=-1 ('a' not found)
foundIndexes.Add(i);
}
long t2 = DateTime.Now.Ticks - t1; // read this value to see the run time
I use the following extension method to yield all results:
public static IEnumerable<int> AllIndexesOf(this string str, string searchstring)
{
int minIndex = str.IndexOf(searchstring);
while (minIndex != -1)
{
yield return minIndex;
minIndex = str.IndexOf(searchstring, minIndex + searchstring.Length);
}
}
usage:
IEnumerable<int> result = "foobar".AllIndexesOf("o"); // [1,2]
Side note to a edge case: This is a string approach which works for one or more characters. In case of "fooo".AllIndexesOf("oo") the result is just 1 https://dotnetfiddle.net/CPC7D2
How about
string xx = "The quick brown fox jumps over the lazy dog";
char search = 'f';
var result = xx.Select((b, i) => b.Equals(search) ? i : -1).Where(i => i != -1);
The raw iteration is always better & most optimized.
Unless it's a bit complex task, you never really need to seek for a better optimized solution...
So I would suggest to continue with :
var foundIndexes = new List<int>();
for (int i = 0; i < myStr.Length; i++)
if (myStr[i] == 'a') foundIndexes.Add(i);
If the string is short, it may be more efficient to search the string once and count up the number of times the character appears, then allocate an array of that size and search the string a second time, recording the indexes in the array. This will skip any list re-allocations.
What it comes down to is how long the string is and how many times the character appears. If the string is long and the character appears few times, searching it once and appending indicies to a List<int> will be faster. If the character appears many times, then searching the string twice (once to count, and once to fill an array) may be faster. Exactly where the tipping point is depends on many factors that can't be deduced from your question.
If you need to search the string for multiple different characters and get a list of indexes for those characters separately, it may be faster to search through the string once and build a Dictionary<char, List<int>> (or a List<List<int>> using character offsets from \0 as the indicies into the outer array).
Ultimately, you should benchmark your application to find bottlenecks. Often the code that we think will perform slowly is actually very fast, and we spend most of our time blocking on I/O or user input.
public static List<int> GetSubstringLocations(string text, string searchsequence)
{
try
{
List<int> foundIndexes = new List<int> { };
int i = 0;
while (i < text.Length)
{
int cindex = text.IndexOf(searchsequence, i);
if (cindex >= 0)
{
foundIndexes.Add(cindex);
i = cindex;
}
i++;
}
return foundIndexes;
}
catch (Exception ex) { }
return new List<int> { };
}
public static String[] Split(this string s,char c = '\t')
{
if (s == null) return null;
var a = new List<int>();
int i = s.IndexOf(c);
if (i < 0) return new string[] { s };
a.Add(i);
for (i = i+1; i < s.Length; i++) if (s[i] == c) a.Add(i);
var result = new string[a.Count +1];
int startIndex = 0;
result[0] = s.Remove(a[0]);
for(i=0;i<a.Count-1;i++)
{
result[i + 1] = s.Substring(a[i] + 1, a[i + 1] - a[i] - 1);
}
result[a.Count] = s.Substring(a[a.Count - 1] + 1);
return result;
}