Related
This question already has answers here:
Iterating through the Alphabet - C# a-caz
(10 answers)
Closed 6 years ago.
I am not sure how to search for this, or I would. What I need to do is count up with letters rather than numbers. the input will only contain letters and numbers, no spaces, or dashes.
For example, if the user enters "A" for start and "ABC" for end it would output, A, B, C,...AA, AB, AC,...ABC.
I can do it by breaking everything down to an array, increase, the last index, until "Z", then, increase the index, check if it is equals end, then loop again.When "Z" is hit and it has a number (treated as a string) start to loop through "0 - 9".
It just seems there would be an easier way, than what I am thinking. I seen one solution in Java that I could convert, but not fully understanding how it works SO Post it is using MOD and does not really compare values. This is just a small project for a computer lab, to generate NetBIOS names, for another program to use. All the names are sequential.
Thanks,
Dave
Dim array1 As String() = {"a", "b", "c"}
Dim array2 As String() = {"a", "b", "c"}
Dim result = array1.SelectMany(Function(f) array2, Function(f, a) New With {Key .first = f, Key .second = a})
Dim s As String = String.Empty
For i As Integer = 0 To result.Count - 1
s += result(i).first + result(i).second + " "
Next
MessageBox.Show(s)
output:
aa
ab
ac
ba
bb
bc
ca
cb
cc
I think this may be close to what you are after. Similar to a cross-join in SQL. This works in VB.Net but you can run a code converter
EDIT: (Ran through code converter (vb to c#), untested)
string[] array1 = {
"a",
"b",
"c"
};
string[] array2 = {
"a",
"b",
"c"
};
dynamic result = array1.SelectMany(f => array2, (f, a) => new {
first = f,
second = a
});
string s = string.Empty;
for (int i = 0; i <= result.Count - 1; i++) {
s += result(i).first + result(i).second + " ";
}
MessageBox.Show(s);
//=======================================================
//Service provided by Telerik (www.telerik.com)
//Conversion powered by NRefactory.
//Twitter: #telerik
//Facebook: facebook.com/telerik
//=======================================================
This question will be mainly opinion based I think, however, I have created my own Base64 ID generator for the visible ID column of my database tables for security reasons, (I saw a video as to why YouTube do it and it made sense although I see other ways of security that probably aren't as problematic). It handles the HIGHLY unlikely event that a duplicate may arise, however, I am curious to know if this is used as a standard for say, YouTube's video IDs.
Program.cs
class Program
{
static void Main(string[] args)
{
var ids = new HashSet<string>();
var count = 0; // for testing only
while (count < 8)
{
ids.Add(Base64Id.GenerateId(ids));
Console.ReadLine();
count++; // for testing only
}
}
}
Base64Id.cs
public static class Base64Id
{
private static int IdSize = 1; // Should be 11
private static readonly string[] AllowedChars = {
"0", "1", "2", "3", "4", "5", "6", "7"//,
//"8", "9", "a", "b", "c", "d", "e", "f",
//"g", "h", "i", "j", "k", "l", "m", "n",
//"o", "p", "q", "r", "s", "t", "u", "v",
//"w", "x", "y", "z", "A", "B", "C", "D",
//"E", "F", "G", "H", "I", "J", "K", "L",
//"M", "N", "O", "P", "Q", "R", "S", "T",
//"U", "V", "W", "X", "Y", "Z", "-", "_"
};
private static Random _random = new Random();
/// <summary>
/// To generate a Base64 ID and check to make sure the ID is not already in use.
/// </summary>
/// <param name="usedIds">List of IDs already in use from the Database or other source.</param>
/// <returns>New Base64 ID</returns>
public static string GenerateId(HashSet<string> usedIds)
{
var autoGenId = "";
do
{
autoGenId = "";
for (var i = 0; i < IdSize; i++)
autoGenId += GetRandomChar();
#if DEBUG
_DEBUG_(usedIds.Count() + 1, autoGenId);
#endif
}
while (IsTaken(autoGenId, usedIds));
return autoGenId;
}
private static string GetRandomChar()
{
var i = _random.Next(0, AllowedChars.Length);
return AllowedChars[i];
}
private static bool IsTaken(string id, HashSet<string> usedIds)
{
var check = usedIds.Any(i => id.Contains(i));
if (check)
return true;
return false;
}
private static void _DEBUG_(int count, string id)
{
Console.WriteLine(String.Format("{0}:\t{1}", count, id));
}
}
I believe that this will work like a charm for my purposes and without any issues, as it does during testing. However, once I narrow it down to 8 chars and with an ID size of length 1, it kicks up serious errors due to the constant looping after only 6 of the 8 expected outputs have happened.
I understand this is from a random number being hit each time and the less that there are to choose from, the more likely the loop must occur.
I know ways to remedy this, however on the scale I plan for, it is crazy to think of, such as having an array/list of every possibility and removing the selected ID.
This is my question;
Do the likes of Youtube know of this problem, and just don't care due to the size of possible IDs.
They just have much greater thought put into the class.
They do not care about the processing cost for such high numbers and handle every small detail.
Or do they use Base64Encode in there code instead of auto-generating it.
I would like to know your opinions and suggestions on how to improve the code or if it even matters which such huge numbers. I have answered with what I think could be possible ways to improve it.
UPDATE
I left two consoles run over the weekend, one using List and the other using HashSet, and the difference between the processed records is on a whole other level. So I have changed the above code to have HashSet instead of List, and set the code up to run automatically.
I believe that for the amount of possible IDs, it is not worth the serious amount of processing it would require to make sure that the ID is unique the further it goes to the end of the list as there are 73,786,976,294,838,206,464 possibilities.
Say for ten possible IDs 1 -> 10, if 2 have been selected already, then the next time, it has a 20% chance of be duplicated, and if 8 have been selected it will be 80% chance, each time. Using probability, this will stack and lower your chances of getting a unique ID to appear.
This is quiet bad once the numbers are low, it took 14539279 iterations the first time and 662984 iterations the second time to get all 8 unique IDs to appear. With bigger numbers I know it will take longer to get to this breaking point, but it will be much worse.
I think that this could be split up into a binary tree once the numbers get bigger as to make the most of it, once each block of say a couple 100k or million reaches 50% or 60% usage, forget the rest and move onto the next range.
I think this could be a good way to try and speed up processing a unique ID into the later stages of the possible list.
I've just a small question about Array.BinarySearch() and about letters what this method somehow doesn't see or cannot recognize.
I created a basic array to try out this method what I've just come across:
string[] Letters1 = { "q", "j", "i", "o" };
int index1 = Array.BinarySearch(Letters1, "q");
Console.WriteLine(index1);
Console.ReadKey();
string[] Letters2 = { "i", "q", "o", "a" };
int index2 = Array.BinarySearch(Letters2, "q");
Console.WriteLine(index2);
Console.ReadKey();
Somehow when start changing the letters and their position it starts giving wrong results
like in the case above...when I have q in first array in the first position and the resultis -5 and in the next array it's displayed correctly.
Binary search only works on ordered collections.
Array.BinarySearch : Searches a one-dimensional sorted Array for a value, using a binary search algorithm.
I have a predefined string array with the letters from A to Q :
string[] SkippedAreasArray = new string[] {"A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q"};
In a TextBox inside Windows Form the user can enter skippedAreas like this: A,B,C,D... there is validations and restrictions to use only letters and commas so the input is guaranteed to be in this format.
What I do is taking the user input and populate another string array:
string[] SkippedAreasFromForm = new string[17];
...
SkippedAreasFromForm = (txtSkippedAreas.Text).Split(',');
Now comes the tricky part for which I'm seeking assistance. The user must enter Number of areas for example - 3. Which mean he is working only with A, B, and C. If the number of areas was 2 then he can only use A and B if the number of areas was 4 then A, B, C and D are available and so on.
What I need is to check if in the array SkippedAreasFromForm which is populated with the user input there is an area that doesn't match the above criteria.
What this mean in terms of coding - I need to take every element from SkippedAreasFromForm, take it's integer value from the predefined SkippedAreasArray and see if this value is equal or greater (>=) of the value that he entered as `Number of areas. If there is an area which is outside the scope of the selected number an error should be shown.
What I have right now is :
foreach (string tempAreaValue in SkippedAreasFromForm)
{
for (int i = 0; i < SkippedAreasArray.Length; i++)
{
if (tempAreaValue == SkippedAreasArray[i])
{
if ((i + 1) > entity.AreasCnt)
{
MessageBox.Show("You must use areas only within the Number of Areas scope!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
txtSkippedAreas.Focus();
return false;
}
}
}
}
For the few test I made it works. But first - at least for me it seems over complicated. Second - I'm not sure that this algorithm is working exactly as I need to or I'm just having correct results by luck. Third - I'm coding C# for 2months now and this seems to me like an excellent candidate for a LINQ expression - do you think it would be better using LINQ and I would appreciate a help in the transformation.
I think you're just looking for IndexOf:
int index = SkippedAreasArray.IndexOf(tempAreaValue);
if (index >= entity.AreasCnt)
{
...
}
(You might also want to check for index being -1, which would occur if the element wasn't in the list at all. Also, consider duplicates - can the user enter A, A, A?)
If you are looking for the elements in the array from start index to max string elements based on areaNumber, then:
int areaNumber = 4;
var result = SkippedAreasArray.Select((r, i) => new { Value = r, Index = i })
.Where(r => r.Index <= areaNumber - 1)
.Select(r => r.Value)
.ToArray();
For areaNumber 4 you will get "A", "B", "C", "D"
EDIT:
I'm looking if every element from the user input (which is array
A,C,H,Q..) is inside the area determined from the areNumber (from comment)
Suppose your userInputArray is:
string[] userInputArray = new string[] {"A", "C", "H", "Q"};
Then you can use Enumerable.Except in the following manner:
if(result.Except(userInputArray).Any())
{
//Invalid
}
else
{
//Valid
}
I have an array for example :
public static string[] elmentnames = { "A", "B", "C", "D", "E","F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R","S", "T", "U", "V", "W", "X", "Y", "Z"};
and I want to select items from index 0 to 15 and put then in a list of string
How?
Presuming the elements are already in the order you want them, you can do it like:
List<string> elementNamesList = elmentnames.Take(15).ToList();
.Take(15) is the first 15 elements. From index 0 to 15 is actually 16 elements, so you can change that to .Take(16) if that's what you meant.
Any of these will work:
var list = elmentnames.Take(16).ToList();
var list = elmentnames.Where((x, i) => i <= 15).ToList();
var array = new string[16];
Array.Copy(elmentnames, array, 16);
var list = new List<string>(array);
You should try creating a for loop that goes threw every element of your current array and ads them to an ArrayList I am not familiar with C# but the concept its the same in every programming language.