Shuffle characters of a string based on a key - c#

I have the following String:
String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
I need to create two strings from it:
A string obtained simply by reordering the characters;
A string obtained by selecting 10 characters and reordering them.
So for (1) I would get, for example:
String characters = "jkDEF56789hisGHIbdefpqraXYZ1234txyzABCcglmnoRSTUVWuvwJKLMNOPQ0";
And for (2) I would get, for example:
String shortList = "8GisIbH9hd";
THE PROBLEM
I could just change to Char Array and order by randomly by a Guid.
However I want to specify some kind of key (maybe a guid?) and for that key the result or reordering and of selecting the shortList must be the same.
Does this make sense?

you could convert your GUID string to an int array of its ascii/utf/whatever codes like here
Getting The ASCII Value of a character in a C# string.
then iterate over this array with something along lines of this (note: this is pseudocode):
string res="";
for(elem in intconvertedGUIDstring) res+= characters[elem%(characters.count)];
for the task [2] you could reverse your Characters i.e. like here Best way to reverse a string
and use the c# string function left() to truncate it before running it through the same procedure

You can use a hash function with a good distribution value as seed for comparison between elements. Here's a sample:
static ulong GetHash(char value, ulong seed)
{
ulong hash = seed * 3074457345618258791ul;
hash += value;
hash *= 3074457345618258799ul;
return hash;
}
And use this function for comparison:
static void Main()
{
var seed = 53ul;
var str = "ABCDEFHYUXASPOIMNJH";
var shuffledStr = new string(str.OrderBy(x => GetHash(x, seed)).ToArray());
Console.WriteLine(shuffledStr);
}
Now every time you order by seed 53 you'll get the same result, and if you seed by 54 you'll get a different result.

Related

Creating Guid using a hash of a string

I'm toying with the idea of using a Guid as a PrimaryKey in a noSQL database thats the combination of three different properties (its probably a bad idea). These three properties are; two integers and a DateTime - they are unique when combined. The reason I'm using a Guid is because preexisting data of same structure uses the Guid instead of the these properties to lookup data.
If I convert them to strings and concat them. Then I convert to byte[] and create a Guid. What are the chances of a collision? I assume the hashing will be the problem here? If I use a weak 16byte hashing algorithm such as MD5 what are the chance of two guid matching (collision) if properties are different; eg integers and datetime? What happens if I use a hashing algorithm like SHA256 and just used the first 16 bytes instead of MD5? Are the odds of collision still the same?
Otherwise I have other options such as a secondary lookup if required but this doubles the writes, reads and cost.
Example:
public static Guid GenerateId(int locationId, int orderNumber, DateTime orderDate)
{
var combined = $"{locationId}{orderNumber}{orderDate.ToString("d", CultureInfo.InvariantCulture)}";
using (MD5 md5 = MD5.Create())
{
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(combined));
return new Guid(hash);
}
}
Why hashing at all? If you are totally sure those three parameters combined are always unique then you have all the data you need to create a unique GUID. DateTime is 8 bytes long, int is 4 bytes long, so your data is 16 bytes long, and that's the exact size of a GUID. You can use BitConverter to get the bytes of those values and use the GUID's constructor that takes a 16 byte array:
DateTime firstValue = DateTime.Now; //Or whatever it is
int secondValue = 33; //whatever
int thirdValue = 44; //whatever
List<byte> tempBuffer = new List<byte>();
tempBuffer.AddRange(BitConverter.GetBytes(firstValue.ToBinary())); //Needs to convert to long first with ToBinary
tempBuffer.AddRange(BitConverter.GetBytes(secondValue));
tempBuffer.AddRange(BitConverter.GetBytes(thirdValue));
Guid id = new Guid(tempBuffer.ToArray());

c# Generate Random number passing long as seed instead of int32

c# Generate Random number passing long as a seed instead of int32, but l need to pass phone numbers or accounts number
https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.8#System_Random__ctor_System_Int32_
Please suggest any reliable NuGet package which does this or any implementation who has already done something like this.
I need to pass the complete PhoneNumber as the seed which I'm able to do in python but not with C# and my code stack is all in C#
using System;
public class Program
{
public static void Main()
{
int seed = 0123456789;
Random random = new Random(seed);
double result = random.NextDouble();
Console.WriteLine(result);
}
}
Some insights on my requirements and what I'm trying to achieve:
1)We're doing this for A/B testing and todo data analysis on the
experience of two services.
2)When a request comes with
phoneNumber based on random.NextDouble() there is a preset percentage
which we use to determine whether to send a request to service A or
service B
3)For example, let's says the request comes and falls
under >0.5 then we direct the request to service A and the next time
the request with the same phone number comes in it will be >0.5 and
goes service A since the seed is a unique hash of phoneNumber.
The method GetHashCode() belongs to Object class, it has nothing to do with random number generation. Please read here (https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.8). The documentation clearly states that it is possible to get collisions specially if input is consistent.
The method HashAlgorithm.ComputeHash (documented here - https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.computehash?view=netframework-4.8) calculates the hash for a given value, but it is consistent in nature, i.e. if input is same, generated output is also same. Obviously this is not the desired output (I assume). I have attached the sample code I tried to generate this.
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
while (true)
{
Console.WriteLine("Enter a 9 digit+ number to calculate hash");
var val = Console.ReadLine();
long target = 0;
bool result = long.TryParse(val,out target);
if (result)
{
var calculatedHash = OutputHash(target);
Console.WriteLine("Calculated hash is : " + calculatedHash);
}
else
{
Console.WriteLine("Incorrect input. Please try again.");
}
}
}
public static string OutputHash(long number)
{
string source = Convert.ToString(number);
string hash;
using (SHA256 sha256Hash = SHA256.Create())
{
hash = GetHash(sha256Hash, source);
Console.WriteLine($"The SHA256 hash of {source} is: {hash}.");
Console.WriteLine("Verifying the hash...");
if (VerifyHash(sha256Hash, source, hash))
{
Console.WriteLine("The hashes are the same.");
}
else
{
Console.WriteLine("The hashes are not same.");
}
}
return hash;
}
private static string GetHash(HashAlgorithm hashAlgorithm, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
var sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
// Verify a hash against a string.
private static bool VerifyHash(HashAlgorithm hashAlgorithm, string input, string hash)
{
// Hash the input.
var hashOfInput = GetHash(hashAlgorithm, input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
return comparer.Compare(hashOfInput, hash) == 0;
}
I agree with #Knoop 's comment above that you might end up with same integer mapping to multiple long number input values.
If you are looking for a 'pure' random number generator with long value as seed, you don't have a choice but to go for third party libraries (or implementing your own custom algorithm). However, rather than getting into such complexities, simple
Guid g = Guid.NewGuid();
should do the trick (https://learn.microsoft.com/en-us/dotnet/api/system.guid.newguid?view=netframework-4.8).
Documentation (https://learn.microsoft.com/en-gb/windows/win32/api/combaseapi/nf-combaseapi-cocreateguid?redirectedfrom=MSDN )says that even this can end up having collisions but chances are very minimal.
Finally, this sounds like potential duplicate of .NET unique object identifier
take the hash of the phone number, eg:
var phoneNumber = 123456789L;
var seed = phoneNumber.GetHashCode();
This means that for the same phoneNumber you will get the same sequence. It also means that for some phone numbers you will get identical sequences, but that is going to be slim. And it might be different on different .net runtimes as commented, but you might not care.
Not sure why you want to, but I there are reasons, e.g. test code

Converting C# to VB - Private String Statement

I have been given some C# code which defined some Private String but I am not sure what it is doing honestly and need to convert into VB for my Project but wandered if someone might take a moment to explain and possible provide a conversion?
private string GetChecksum(StringBuilder buf)
{
// calculate checksum of message
uint sum = 0;
for (int i = 0; i < buf.Length; i++)
{
sum += (char)buf[i];
}
return string.Format("{0:X04}", sum);
}
The part with private string ... is the method declaration. C#'s
Accessibility ReturnType MethodName(Type paramName)
translates to
Accessibility Function MethodName(paramName As Type) As ReturnType
Private Function GetChecksum(buf As StringBuilder) As String
'calculate checksum of message
Dim sum As UInteger = 0
For i As Integer = 0 To buf.Length - 1
sum += CChar(buf(i))
Next
Return String.Format("{0:X04}", sum)
End Function
What the function does is adds up the ASCII values of each character in the string (stored in a 2-byte char without overflow checking) and return the result as a string - the 4-character hexadecimal representation of the 2-byte result.
A checksum is used to detect data errors; if two strings yield different checksums then they cannot be equal. Two strings that give the same checksum, however, are non necessarily equal, so it cannot be used to verify equality.

Convert String to Int (NOT PARSE)

How can i get the numeric representation of a string in C#? To be clear, I do not want the address of the pointer, I do not want to parse an int from a string, I want the numeric representation of the value of the string.
The reason I want this is because I am trying to generate a hash code based on a file path (path) and a number (line). I essentially want to do this:
String path;
int line;
public override int GetHashCode() {
return line ^ (int)path;
}
I'm up to suggestions for a better method, but because I'm overriding the Equals() method for the type I'm creating (to check that both object's path and line are the same), I need to reflect that in the override of GetHashCode.
Edit: Obviously this method is bad, that has been pointed out to me and I get that. The answer below is perfect. However, it does not entirely answer my question. I still am curious if there is a simple way to get an integer representation of the value of a string. I know that I could iterate through the string, add the binary representation of that char to a StringBuffer and convert that string to an int, but is there a more clean way?
Edit 2: I'm aware that this is a strange and very limited question. Converting in this method limits the size of the string to 2 chars (2 16 bit char = 1 32 bit int), but it was the concept I was getting at, and not the practicality. Essentially, the method works, regardless of how obscure and useless it may be.
If all you want is a HashCode, why not get the hashcode of the string too? Every object in .net has a GetHashCode() function:
public override int GetHashCode() {
return line ^ path.GetHashCode();
}
For the purposes of GetHashCode, you should absolutely call GetHashCode. However, to answer the question as asked (after clarification in comments) here are two options, returning BigInteger (as otherwise you'd only get two characters in before probably overflowing):
static BigInteger ConvertToBigInteger(string input)
{
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(input);
// BigInteger constructor expects a little-endian byte array
Array.Reverse(bytes);
return new BigInteger(bytes);
}
static BigInteger ConvertToBigInteger(string input)
{
BigInteger sum = 0;
foreach (char c in input)
{
sum = (sum << 16) + (int) c;
}
return sum;
}
(These two approaches give the same result; the first is more efficient, but the second is probably easier to understand.)

How would you create a unique random number that isn't in a list?

I'm trying to create a method that stores a unique random number to a class, and the way I am checking if it is unique is by looking through a list that contains an int, string and date. I'm just sort of stuck on how you would have it just search the ints of the list.
You can use a guid, is based in your computer id and date. Is by definition a unique string every time.
use Guid.NewGuid()
Well if it is just numbers you can use a mathematical function like this one here then use the current date to limit our possible numbers and use the random functions to generate your unique number.
You can use in c# this DateTime.Ticks to get there.
Use Math.Random Class. See here i m using this class to generate password. You can specify what are the data it should support. if you need integer only then you can specify (1 to 9 and 0). Here is one example.
private string CreatePassword(int length)
{
string valid = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz##$";
string res = "";
Random rnd = new Random();
while (0 < length--)
res += valid[rnd.Next(valid.Length)];
return res;
}
public void InitializeData()
{
string password = CreatePassword(6);
}

Categories