Hash a small integer value to a big 16 digit unique number - asp.net

I've a situation to create a 16 digit number from another integer. It should be like a credit card number. So what is our scenario is if that users ID is 1 or 2, that should be hashed to a 16 digit string (Numeric). So that 16 digit should be unique for 1
I tried to .NET builtin functions like generate hash etc.
That doesn't helped me for a perfect solution

Not sure how many users you expect, but this code produces 16 digit integers and using the numbers from 1 to 100 there were no repeats:
Imports System.Security.Cryptography
Dim sha As New SHA1CryptoServiceProvider()
Dim IntList As New List(Of ULong)
For I = 1 To 100000
'Need a byte array for the ComputeHash method
Dim data() As Byte = BitConverter.GetBytes(I)
If BitConverter.IsLittleEndian Then Array.Reverse(data)
'Store the 160 bit hash in a byte array
Dim result As Byte() = sha.ComputeHash(data)
'Bitconverter's result can be too long, so by taking the first 16 digits _
of the results that are too long, and padding the rest to the right with _
0's we end up with unique 16 digit integers
Dim HashInt As ULong = ULong.Parse(BitConverter.ToUInt64(result, 0).ToString.PadRight(16, "0"c).Substring(0, 16))
'Using a list to hold the hash's is just to confirm that each one is unique. _
for the your purposes I would suggest a dictionary(of integer, ulong)
If Not IntList.Contains(HashInt) Then
IntList.Add(HashInt)
End If
Next
UPDATE: modified the code to show that it will produce 100000 unique hash's. IntList.Count = 100000.
For results that end up being less than 16 digits, I padded the end with 0's. This is just convenient. By putting the BitConverter.ToUInt64 result into a string you can insert the 0's anywhere you like.

Maybe you could use this:
string SixteenDigitHash(int value)
{
var rnd = new Random(value);
StringBuilder sb = new StringBuilder(16);
sb.Append(rnd.Next(1,10)); // first digit 1..9
for (int i=1; i<16; i++)
{
sb.Append(rnd.Next(0,10)); // other digits 0..9
}
return sb.ToString();
}
It uses Random to generate (pseudo) random numbers, but uses the value-to-hash as seed so it always generates the same sequence for a given value and different sequences for different values.
One problem: the sequence is not guaranteed to be the same for different versions of the framework. Maybe you should use your own implementation of that Random class so that you know that the sequence is stable.

Related

Encode numbers with letters with fixed lentgh?

I have two unique numbers, 100000 - 999999 (fixed 6 chars length [0-9]), second
1000000 - 9999999 (fixed 7 char length [0-9]). How can i encode/decode this numbers (they need to remain separate after decoding), using only uppercase letters [A-Z] and [0-9] digits and have a fixed length of 8 chars in total?
Example:
input -> num_1: 242404, num_2 : 1002000
encode -> AX3B O3XZ
decode -> 2424041002000
Is there any algorithm for this type of problem?
This is just a simple mapping from one set of values to another set of values. The procedure is always the same:
List all possible input and output values.
Find the index of the input.
Return the value of the output list at that index.
Note that it's often not necessary to make an actual list (i.e. loading all values into some data structure). You can typically compute the value for any index on-demand. This case is no different.
Imagine a list of all possible input pairs:
0 100'000, 1'000'000
1 100'000, 1'000'001
2 100'000, 1'000'002
...
K 100'000, 9'999'999
K+1 100'001, 1'000'000
K+2 100'001, 1'000'001
...
N-1 999'999, 9'999'998
N 999'999, 9'999'999
For any given pair (a, b), you can compute its index i in this list like so:
// Make a and b zero-based
a -= 100'000
b -= 1'000'000
i = a*1'000'000 + b
Convert i to base 36 (A-Z and 0-9 gives you 36 symbols), pad on the left with zeros as necessary1, and insert a space after the fourth digit.
encoded = addSpace(zeroPad(base36(i)))
To get back to the input pair:
Convert the 8-character base 36 string to base 10 (this is the index into the list, remember), then derive a and b from the index.
i = base10(removeSpace(encoded))
a = i/1'000'000 + 100'000 // integer divison (i.e. ignore remainder)
b = i%1'000'000 + 1'000'000
Here is an implementation in Go: https://play.golang.org/p/KQu9Hcoz5UH
1 If you don't like the idea of zero padding you can also offset i at this point. The target set of values is plenty big enough, you need only about 32% of all base 36 numbers with eight digits or less.

astyanax column slice query how to do inclusive and exclusive column slice

I have a composite column that I can do inclusive and exclusive on both ends of a range like so
AnnotatedCompositeSerializer serializer = info1.getCompositeSerializer();
CompositeRangeBuilder range = serializer.buildRange();
if(fromInclusive)
range = range.greaterThanEquals(from);
else
range = range.greaterThan(from);
if(toInclusive)
range = range.lessThanEquals(to);
else
range = range.lessThan(to);
return range;
GREAT so far, but when I have a normal column family with no composite names where the names are either Integer, Decimal, or String, how do I do the same thing. Right now I just have
ByteBufferRange range = new RangeBuilder().setStart(from).setEnd(to).setLimit(batchSize).build();
but there are no methods for inclusive/exclusive.
How to do this one?
NOTE: Integer and Decimal CAN be two's complement so they could start with fffff and who knows how long the values are since they can be as big as someone wants.
thanks,
Dean

Data set skip column

I have one dataset in which i have say 10 rows..
I want to skip data of first two column means whatever data is there in that first 2 column
sholud not present in that dataset how to do this..?
What is the reason? Are you trying to do this, because you did not want it to appear in the DataGrid... Or are you trying to do some merge operations...
If for datagrid, you can just hide those columns in the DataGrid/Gridview...
If it is otherwise you can remove the columns as stated by Tim...
If you mean a Datatable instead of a dataset you can remove colums:
Dim removeCount As Int32 = 2
For i As Int32 = 1 To removeCount
For ii As Int32 = 0 To myDataTable.Columns.Count - 1
If myDataTable.Columns.CanRemove(myDataTable.Columns(ii)) Then
myDataTable.Columns.RemoveAt(ii)
Exit For
End If
Next
Next
Removes the two first columns(if they are removable and not primary keys).
Or even simpler, when removing the primary key from the datatable is acceptable:
For i As Int32 = 1 To removeCount
If Not myDataTable.Columns.CanRemove(myDataTable.Columns(0)) Then
myDataTable.PrimaryKey = Nothing
End If
myDataTable.Columns.RemoveAt(0)
Next

Randomize numbers in VB.NET without using a range i.e. Min and Max

I was wondering if anyone can point me in the right direction please? Say I am pulling the following table, I would then like to select an ID randomly. I understand how to select a random number using a Randomize() call followed by the relevant syntax but I want to pre-define the range.
i.e. Table Data
ID | Name
4345 Mike
3456 Lee
4567 John
There will be many more names but for this example you could use 3 or 4 etc..
Please help I'm starting to itch :o|
Just to make sure I understand what you want:
Given a table, you want to randomly select one of the ID values from that table.
If so, this should do it:
Dim rand As New Random()
Dim record As Integer = rand.[Next](0, myDataTable.Rows.Count)
Dim randomID As Integer = CInt(myDataTable.Rows(record)("ID"))
We have all the information we need to randomly select a row, and by extension randomly select one of the ID values in the table.
In old Vb you would do
Dim i as integer
i = (Rnd * (maxval-minval)) + minval
Since rnd returns a random number between 0 and 1 you would scale the number to the right range.

A way of checking if the digits of num1 are the digits in num2 without checking each digit?

Lets say I have guessed a lottery number of:
1689
And the way the lottery works is, the order of the digits don't matter as long as the digits match up 1:1 with the digits in the actual winning lottery number.
So, the number 1689 would be a winning lottery number with:
1896, 1698, 9816, etc..
As long as each digit in your guess was present in the target number, then you win the lottery.
Is there a mathematical way I can do this?
I've solved this problem with a O(N^2) looping checking each digit against each digit of the winning lottery number (separating them with modulus). Which is fine, it works but I want to know if there are any neat math tricks I can do.
For example, at first... I thought I could be tricky and just take the sum and product of each digit in both numbers and if they matched then you won.
^ Do you think that would work?
However, I quickly disproved this when I found that lottery guess: 222, and 124 have the different digits but the same product and sum.
Anyone know any math tricks I can use to quickly determine if the digits in num1 match the digits in num2 regardless of order?
How about going through each number, and counting up the number of appearances of each digit (into two different 10 element arrays)? After you'd done the totaling, compare the counts of each digit. Since you only look at each digit once, that's O(N).
Code would look something like:
for(int i=0; i<digit_count; i++)
{
guessCounts[guessDigits[i] - '0']++;
actualCounts[actualDigits[i] - '0']++;
}
bool winner = true;
for(int i=0; i<10 && winner; i++)
{
winner &= guessCounts[i] == actualCounts[i];
}
Above code makes the assumption that guessDigits and actualDigits are both char strings; if they held the actual digits then you can just skip the - '0' business.
There are probably optimizations that would make this take less space or terminate sooner, but it's a pretty straightforward example of an O(N) approach.
By the way, as I mentioned in a comment, the multiplication/sum comparison will definitely not work because of zeros. Consider 0123 and 0222. Product is 0, sum is 6 in both cases.
Split into array, sort array, join into string, compare strings.
(Not a math trick, I know)
You can place the digits into an array, sort the array, then compare the arrays element by element. This will give you O( NlogN ) complexity which is better than O( N^2 ).
If N can become large, sorting the digits is the answer.
Because digits are 0..9 you can count the number of occurrences of each digit of the lottery answer in an array [0..9].
To compare you can subtract 1 for each digit you encounter in the guess. When you encounter a digit where the count is already 0, you know the guess is different. When you get through all the digits, the guess is the same (as long as the guess has as many digits as the lottery answer).
For each digit d multiply with the (d+1)-th prime number.
This is more mathematical but less efficient than the sorting or bucket methods. Actually it is the bucket method in disguise.
I'd sort both number's digits and compare them.
If you are only dealing with 4 digits I dont think you have to put much thought into which algorithm you use. They will all perform roughly the same.
Also 222 and 124 dont have the same sum
You have to consider that when n is small, the order of efficiency is irrelevant, and the constants start to matter more. How big can your numbers actually get? Can you get up to 10 digits? 20? 100? If your numbers have just a few digits, n^2 really isn't that bad. If you have strings of thousands of digits, then you might actually need to do something more clever like sorting or bucketing. (i.e. count the 0s, count the 1s, etc.)
I'm stealing the answer from Yuliy, and starblue (upvote them)
Bucketing is the fastest aside from the O(1)
lottonumbers == mynumbers;
Sorting is O(nlog2n)
Bucketsort is an O(n) algorithm.
So all you need to do is do it twice (once for your numbers, once for the target-set), and if the numbers of the digits add up, then they match.
Any kind of sorting is an added overhead that is unnecessary in this case.
array[10] digits;
while(targetnum > 0)
{
short currDig = targetnum % 10;
digits[currDig]++;
targetnum = targetnum / 10;
}
while(mynum > 0)
{
short myDig = mynum % 10;
digits[myDig]--;
mynum = mynum / 10;
}
for(int i = 0; i < 10; i++)
{
if(digits[i] == 0)
continue;
else
//FAIL TO MATCH
}
Not the prettiest code, I'll admit.
Create an array of 10 integers subscripted [0 .. 9].
Initialize each element to a different prime number
Set product to 1.
Use each digit from the number, to subscript into the array,
pull out the prime number, and multiply the product by it.
That gives you a unique representation which is digit order independent.
Do the same procedure for the other number.
If the unique representations match, then the original numbers match.
If there are no repeating digits allowed (not sure if this is the case though) then use a 10-bit binary number. The most significant bit represents the digit 9 and the LSB represents the digit 0. Work through each number in turn and flip the appropriate bit for each digit that you find
So 1689 would be: 1101000010
and 9816 would also be: 1101000010
then a XOR or a subtract will leave 0 if you are a winner
This is just a simple form of bucketing
Just for fun, and thinking outside of the normal, instead of sorting and other ways, do the deletion-thing. If resultstring is empty, you have a winner!
Dim ticket As String = "1324"
Dim WinningNumber As String = "4321"
For Each s As String In WinningNumber.ToCharArray
ticket = Replace(ticket, s, "", 1, 1)
Next
If ticket = "" Then MsgBox("WINNER!")
If ticket.Length=1 then msgbox "Close but no cigar!"
This works with repeating numbers too..
Sort digits before storing a number. After that, your numbers will be equal.
One cute solution is to use a variant of Zobrist hashing. (Yes, I know it's overkill, as well as probabilistic, but hey, it's "clever".)
Initialize a ten-element array a[0..9] to random integers. Then, for each number d[], compute the sum of a[d[i]]. If the numbers contained the same digits, the resulting numbers will be equal; with high probability (~ 1 in how many possible ints there are), the opposite is true as well.
(If you know that there will be at most 10 digits total, then you can use the fixed numbers 1, 10, 100, ... instead of random numbers for guaranteed success. This is bucket sorting in not-too-much disguise.)

Resources