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.
Related
I want to get a string offset of file, but the string offset changes file to file.
So, I did make a custom dictionary.
[0x41] = "A",
[0x42] = "B",
[0x43] = "C",
[0x44] = "D",
[0x45] = "E",
[0x46] = "F",
[0x47] = "G",
.....................
To get the offset, i want to read the file, when finds 5 sequential chars of my dictionary, stop then back -5 and then get offset.
Can someone help me?
I may not know how to search for a solution properly yet but I could not find anything related to the thing I got stuck on below:
I have a List of strings containing 21 words
public static List<string> LevelOneWords = new List<string> { "As", "If", "Go", "Do", "So", "No", "Up", "Hi", "Me", "Be", "Ah", "An", "Aw", "Is", "Ok", "At", "We", "Am", "Ab", "Ex", "It"};
How do I go on about generating a specific amount of these following a user decision?
Because rand.Next(LevelOneWords.Count) only lets you generate random words from the amount available in the list.
But say I wanted to generate 50 instances?
To put you in the picture, this is a Typer Shark kind of game and in the training session, I want the user to have the freedom to choose how much words should be generated.
Thanking you in advance since I am new to programming and I find StackOverFlow's community very helpful!
You can use rand.Next() X times using a loop:
List<string> selectedWords = new List<string>();
for (int i = 0; i < 50; ++i)
{
string randomWord = LevelOneWords[rand.Next(LevelOneWords.Count)];
selectedWords.Add(randomWord);
}
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.