I'm wondering if it is possible to enumerate over the alphabet from 'a' to 'zzz'?
For example I have a cave system that contains a maximum of 1000 caves and I would like to assign a char value to each of them.
1 = a, 2 = b, 3 = c ... 27 = aa etc
What would be the best way to go about doing this if it is possible?
void Main()
{
foreach (string word in EnumerateCaveNames())
Console.WriteLine(word);
}
IEnumerable<string> EnumerateCaveNames()
{
for (int i = 0; i < 26 * 26 * 26; ++i)
{
yield return BuildCaveName(i);
}
}
string BuildCaveName(int caveNum)
{
string name = (GetLetterFromNumber(caveNum / (26 * 26)) + GetLetterFromNumber((caveNum / 26) % 26) + GetLetterFromNumber(caveNum % 26)).TrimStart('a');
if (name == "")
name = "a";
return name;
}
string GetLetterFromNumber(int num)
{
return "" + (char)('a' + num);
}
It's like a converter for excel columns :
How to convert a column number (eg. 127) into an excel column (eg. AA)
private string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
Related
So the problem that I'm trying to optimize is to find and print all four-digit numbers of the type ABCD for which: A + B = C + D.
For example:
1001
1010
1102
etc.
I have used four for loops to solve this (one for every digit of the number).
for (int a = 1; a <= 9; a++)
{
for (int b = 0; b <= 9; b++)
{
for (int c = 0; c <= 9; c++)
{
for (int d = 0; d <= 9; d++)
{
if ((a + b) == (c + d))
{
Console.WriteLine(" " + a + " " + b + " " + c + " " + d);
}
}
}
}
}
My question is: how can I solve this using only 3 for loops?
Here's an option with two loops (though still 10,000 iterations), separating the pairs of digits:
int sumDigits(int input)
{
int result = 0;
while (input != 0)
{
result += input % 10;
input /= 10;
}
return result;
}
//optimized for max of two digits
int sumDigitsAlt(int input)
{
return (input % 10) + ( (input / 10) % 10);
}
// a and b
for (int i = 0; i <= 99; i++)
{
int sum = sumDigits(i);
// c and d
for (int j = 0; j <= 99; j++)
{
if (sum == sumDigits(j))
{
Console.WriteLine( (100 * i) + j);
}
}
}
I suppose the while() loop inside of sumDigits() might count as a third loop, but since we know we have at most two digits we could remove it if needed.
And, of course, we can use a similar tactic to do this with one loop which counts from 0 to 9999, and even that we can hide:
var numbers = Enumerable.Range(0, 10000).
Where(n => {
// there is no a/b
if (n < 100 && n == 0) return true;
if (n < 100) return false;
int sumCD = n % 10;
n /= 10;
sumCD += n % 10;
n /= 10;
int sumAB = n % 10;
n /= 10;
sumAB += n % 10;
return (sumAB == sumCD);
});
One approach is to write a method that takes in an integer and returns true if the integer is four digits and the sum of the first two equal the sum of the second two:
public static bool FirstTwoEqualLastTwo(int input)
{
if (input < 1000 || input > 9999) return false;
var first = input / 1000;
var second = (input - first * 1000) / 100;
var third = (input - first * 1000 - second * 100) / 10;
var fourth = input - first * 1000 - second * 100 - third * 10;
return (first + second) == (third + fourth);
}
Then you can write a single loop from 1000-9999 and output the numbers for which this is true with a space between each digit (not sure why that's the output, but it appears that's what you were doing in your sample code):
static void Main(string[] args)
{
for (int i = 1000; i < 10000; i++)
{
if (FirstTwoEqualLastTwo(i))
{
Console.WriteLine(" " + string.Join(" ", i.ToString().ToArray()));
}
}
Console.Write("Done. Press any key to exit...");
Console.ReadKey();
}
We can compute the value of d from the values of a,b,c.
for (int a = 1; a <= 9; a++)
{
for (int b = 0; b <= 9; b++)
{
for (int c = 0; c <= 9; c++)
{
if (a + b >= c && a + b <= 9 + c)
{
int d = a + b - c;
Console.WriteLine(" " + a + " " + b + " " + c + " " + d);
}
}
}
}
We can further optimize by changing the condition of the third loop to for (int c = max(0, a + b - 9); c <= a + b; c++) and getting rid of the if statement.
I am trying to find a way to increment a user defined idenitifer. I have written something that achieves what I want the code to do, but I highly doubt it's the best way to do this:
The character pattern is:
AAA000
AAA999
BAA000
BAA999
BBA000
And so on, although:
AAA000
AAA999
BAA000
BAA999
CAA000
Would be acceptable.
Here is my code to just generate that pattern:
int i = 30;
char char1 = 'A';
char char2 = 'A';
char char3 = 'A';
double number = 998;
for (int j = 0; j < i; j++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
if (number == 999)
{
number = 998;
if (char1 == char2 && char1 == char3 && char1 != 'Z')
{
char1++;
}
else if (char1 > char2 && char2 != 'Z')
{
char2++;
}
else if (char3 != 'Z')
{
char3++;
}
}
else
{
number++;
}
Console.WriteLine(id);
}
To clarify, I need to build a function that can take the latest value, for example:
DEF123
which in turn will return:
DEF124
Or DEF999 which will return DEG000.
Using Maximillians answer, I have amended the method:
static void NextId(string highestId)
{
char startChar1 = highestId[0];
char startChar2 = highestId[1];
char startChar3 = highestId[2];
int startNumber = int.Parse(highestId.Substring(highestId.Length - 3));
int n = 1;
int i = 0;
for (char char1 = startChar1; char1 <= 'Z' && i < n; char1++)
{
for (char char2 = startChar2; char2 <= 'Z' && i < n; char2++)
{
for (char char3 = startChar3; char3 <= 'Z' && i < n; char3++)
{
for (int number = startNumber; number < 1000 && i < n; number++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
Console.WriteLine(id);
i++;
}
}
}
}
}
This is almost perfect, except:
DEZ998 returns DEZ998, DEZ999 being the highest id passed in returns DEZ999.
Any recommendations on achieving this would be a great help.
I had to do some assumptions on your pattern, but as far as I understood your question I'd use nested loops instead one loop to rule them all.
int n = 30;
int i = 0;
for (char char1 = 'A'; char1 <= 'Z' && i < n; char1++)
{
for (char char2 = 'A'; char2 <= 'Z' && i < n; char2++)
{
for (char char3 = 'A'; char3 <= 'Z' && i < n; char3++)
{
for(int number = 0; number < 1000 && i < n; number++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
Console.WriteLine(id);
i++;
}
}
}
}
This will:
Increment the number from 0 to 999
Afterwards it'll increment Char1 by one and start again at (1.) until Z is reached
Afterwards it'll increment Char2 by one and start again at (2.) until Z is reached
Afterwards it'll increment Char3 by one and start again at (3.) until Z is reached
It will stop at any point if the maximum amount(n) is reached
→ You will get a maximum amout of 17575999 possible unique ID's
Update:
The method GetNextId(Tuple<char, char, char, int> id) could help you for that. It calculates the next ID depending on the previous one.
void GenerateIDs()
{
char char1 = 'B';
char char2 = 'F';
char char3 = 'A';
int number = 159;
int n = 30;
// this one is the current ID
var iterationId = new Tuple<char, char, char, int>(char1, char2, char3, number);
for(int i = 1; i < n; i++)
{
iterationId = GetNextId(iterationId);
Console.WriteLine(IdToString(iterationId));
}
}
/// returns: c1Next, c2Next, c3Next, numberNext
private Tuple<char, char, char, int> GetNextId(Tuple<char, char, char, int> id)
{
var number = id.Item4 + 1;
var c3 = id.Item3;
var c2 = id.Item2;
var c1 = id.Item1;
if(number > 999)
{
number = 0;
c3++;
if(c3 > 'Z')
{
c3 = 'A';
c2++;
if (c2 > 'Z')
{
c2 = 'A';
c1++;
if(c1 > 'Z')
{
throw new IndexOutOfRangeException("Next ID bigger than \"ZZZ999\"");
}
}
}
}
return new Tuple<char, char, char, int>(c1, c2, c3, number);
}
private string IdToString(Tuple<char, char, char, int> id)
{
return $"{id.Item1}{id.Item2}{id.Item3}{id.Item4.ToString().PadLeft(3, '0')}";
}
Alternatevly
You could just store an int to the database and use the values 0 to 17575999 and then calculate the display ID
private string IntToId(int intId)
{
var number = intId % 1000;
intId /= 1000;
char c3 = (char) ('A' + (intId % 26));
intId /= 26;
var c2 = (char) ('A' + (intId % 26));
intId /= 26;
var c1 = (char) ('A' + (intId % 26));
return $"{c1}{c2}{c3}{number.ToString().PadLeft(3, '0')}";
}
private int IdToInt(string id)
{
int c1 = id[0] - 'A';
int c2 = id[1] - 'A';
int c3 = id[2] - 'A';
int number = Int32.Parse(id.Substring(3));
return ((((((c1 * 26) + c2) *26) + c3) * 1000) + number);
}
When I do an xor on a string I get special characters
private void btnEncryptDecrypt_Click(object sender, EventArgs e)
{
byte[] bytes = Encoding.UTF8.GetBytes(keyTextBox.Text);
textTextBox.Text = string.Empty;
foreach (byte i in bytes)
{
byte c = Convert.ToByte(i ^ Convert.ToByte(textBox1.Text));
textTextBox.Text = textTextBox.Text + Convert.ToChar(c);
}
}
62FA7AC4 1234567890 xor to !%QV VT#7&%$#"! /.'
I want to use it for serial key generation with only alphanumeric characters
I want to pass "62FA7AC4", a date and a number between 0 and 5000 and a few random dummy numbers
Input will be "62FA7AC4"+"2500"+"21/05/2018"
Output should be something like "5QBK-J4D1-8CF6-5MW2-78FZ-2FPL-4S6S-CTGB"
What am I doing Wrong?
Try working with numbers, not strings:
using System.Numerics;
...
// Let's use BigInteger for arbitrary long values
BigInteger left = BigInteger.Parse("62FA7AC4", NumberStyles.HexNumber);
BigInteger right = BigInteger.Parse("1234567890", NumberStyles.HexNumber);
string result = (left ^ right).ToString("X");
Console.Write(result);
So you have
1256AC0254
Edit: As far as I can see you want alphanumeric (i.e. Base 36 == 26 letters + 10 digits output). You can use the same approach: operate with integer(s), not string(s)
private static Random s_Random = new Random();
...
BigInteger value = BigInteger.Parse(
"0" + // we don't want negative values
"62FA7AC4" + // header
s_Random.Next(5001).ToString("0000") + // random in [0..5000] range
DateTime.Today.ToString("ddMMyyyy"), // Date like 21052018
NumberStyles.HexNumber);
Then do any xor (if you like):
value ^= some_secret_value;
Finally represent the value in base 36:
private static String ToBase36(BigInteger value) {
List<char> list = new List<char>();
for (int index = 0; value > 0; value /= 36, index++) {
if (index > 0 && index % 4 == 0)
list.Add('-');
BigInteger v = value % 36;
list.Add(v < 10 ? (char)('0' + v) : (char) ('A' + v - 10));
}
list.Reverse();
return string.Concat(list);
}
Test:
BigInteger value = BigInteger.Parse(
"0" +
"62FA7AC4" +
"2500" +
DateTime.Today.ToString("ddMMyyyy"),
NumberStyles.HexNumber);
string result = ToBase36(value);
Console.Write(result);
Outcome:
2443-WNC5-AVBB-M32W
Edit 2: To restore the original number
private static BigInteger FromBase36(string value) {
BigInteger result = 0;
BigInteger power = 1;
for (int i = value.Length - 1; i >= 0; --i) {
char item = value[i];
if (item >= '0' && item <= '9') {
result += power * (item - '0');
power *= 36;
}
else if (item >= 'A' && item <= 'Z') {
result += power * (item - 'A' + 10);
power *= 36;
}
else if (item >= 'a' && item <= 'z') {
result += power * (item - 'a' + 10);
power *= 36;
}
}
return result;
}
e.g.
BigInteger value = BigInteger.Parse(
"0" +
"62FA7AC4" +
"2500" +
DateTime.Today.ToString("ddMMyyyy"),
NumberStyles.HexNumber);
string result = ToBase36(value);
BigInteger back = FromBase36(result);
Console.WriteLine(string.Join(Environment.NewLine, value, result, back));
Outcome:
467412447575903165554712
2443-WNC5-AVBB-M32W
467412447575903165554712
This question already has answers here:
How to convert a column number (e.g. 127) into an Excel column (e.g. AA)
(60 answers)
Closed 5 years ago.
I have a requirement for a custom number system in C# which goes as following:
A - 1
B - 2
...
Z - 26
AA - 27
AB - 28
I've made a function that converts from arbitrary strings to numbers like this:
private const int Min = 'A';
private const int Max = 'Z';
private const int Base = Max - Min + 1;
private static int GetCharValue(char c)
{
if (c < Min || c > Max)
throw new ArgumentOutOfRangeException(nameof(c), c, $"Character needs to be between '{Min}' and '{Max}', was '{c}'.");
return c - Min + 1;
}
public static int GetStringValue(string s)
{
char[] chars = s.ToCharArray();
int[] values = new int[chars.Length];
for (var i = 0; i < chars.Length; i++)
{
values[i] = GetCharValue(chars[i]);
}
int position = 1;
int value = 0;
for (var i = values.Length - 1; i >= 0; i--)
{
value += position * values[i];
position *= Base;
}
return value;
}
I've tested it to be working for up to AAA (not rigorously, just skimming over the output of printing them all). However, I can't for the life of me figure out how to write the reverse function. In other words, I need 1 to return A, 26 to return Z and 27 to return AA. The "problem" is that this number system has no 0, so it doesn't easily convert to any base. For instance, if A was 0, then AA would also be 0, but it's not. So how do I solve this?
you can simply generate it like this....
public static IEnumerable<string> generate()
{
long n = -1;
while (true) yield return toBase26(++n);
}
public static string toBase26(long i)
{
if (i == 0) return ""; i--;
return toBase26(i / 26) + (char)('A' + i % 26);
}
public static void BuildQuery()
{
IEnumerable<string> lstExcelCols = generate();
try
{
string s = lstExcelCols.ElementAtOrDefault(1) ;
}
catch (Exception exc)
{
}
}
How to find column's name or header?
For example if i select column 5 in excel means i want the result as "E".
How to get the alphabet or letter corresponding to column no.
Please help me with the code
public static string GetColumnName(int columnNumber)
{
const string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string columnName = "";
while (columnNumber > 0)
{
columnName = letters[(columnNumber - 1) % 26] + columnName;
columnNumber = (columnNumber - 1) / 26;
}
return columnName;
}
What about using Application.ActiveCell.get_Address(true, true, Excel.AlReferenceStyle.xlA1, missing, missing) and then parse the result string or use a RegEx to get the column heading?
I simply used:
string location = Application.ActiveCell.get_Address(true, true, Excel.AlReferenceStyle.xlA1, missing, missing);
string tokens = x.Split("$".ToCharArray());
MessageBox.Show(String.Format("Column {0}", result[0]));
public static long GetColumnNumber(string columnName)
{
int letterPos = 0;
long columnNumber = 0;
for (int placeHolder = columnName.Length - 1; placeHolder >= 0; placeHolder--)
{
int currentSum = 1;
for (int multiplier = 0; multiplier < placeHolder; multiplier++)
currentSum *= 26;
int letterValue = (int) columnName[letterPos];
currentSum *= letterValue - 64;
columnNumber += currentSum;
if (letterPos != columnName.Length)
letterPos++;
//Console.WriteLine(((int)columnName[i]-64) + " = " + columnName[i]);
}
return columnNumber;
}
The following is a complete method which gives you the corresponding alphabet for an integer value that is passed.
private String Number2String(int number, bool isCaps)
{
int number1 = number / 27;
int number2 = number - (number1 * 26);
if (number2 > 26)
{
number1 = number1 + 1;
number2 = number - (number1 * 26);
}
Char a = (Char)((isCaps ? 65 : 97) + (number1 - 1));
Char b = (Char)((isCaps ? 65 : 97) + (number2 - 1));
Char c = (Char)((isCaps ? 65 : 97) + (number - 1));
string d = String.Concat(a, b);
if (number <= 26)
return c.ToString();
else
return d;
}
I use these two:
public string GetExcelColumn(int index)
{
int quotient = index / 26;
if (quotient > 0)
return GetExcelColumn(quotient - 1) + (char)((int)'A' + (index % 26));
else
return "" + (char)((int)'A' + index);
}
static IEnumerable<string> GetExcelColumns()
{
var alphabet = new string[]{""}.Union(from c in Enumerable.Range((int)'A', 26) select Convert.ToString((char)c));
return from c1 in alphabet
from c2 in alphabet
from c3 in alphabet.Skip(1) // c3 is never empty
where c1 == string.Empty || c2 != string.Empty // only allow c2 to be empty if c1 is also empty
select c1 + c2 + c3;
}
This works well in VBA by using a double replace, where R is a Single Cell Excel Range:
ColumnLetter = Replace(Replace(R.AddressLocal(ReferenceStyle:=1), "$", vbNullString), R.Row, vbNullString)
It is based on the equivalent idea for use on a Worksheet. In a Cell Formula use this, it is even shorter:
=SUBSTITUTE(ADDRESS(1,COLUMN(M1),4),1,"")
This returns the letter M and works right up to Column XFD. The cell reference M1 can be any Range anywhere. The top left Column is returned for Ranges or more than one cell.
It gets the ADDRESS of the first Cell in the Column and then removes the trailing 1 by substituting a NullString for it. (The 4 in the ADDRESS makes sure that the Address is returned as a Relative Address, i.e. one without and $ signs in it.)
Thanks to barry houdini who set me off on the quest for a good answer to this.