Perfect hash function (i.e. no collisions) with same length [closed] - python

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
I'm looking for a simple hash function that yields no collisions.
I have an alphanumeric sequence (say 16 letter long) and I want each one of them to map to unique hashed value. Ideally, the hashed value is the same length as the original sequence (16 letter long).
Is there a simple python hash function that achieves this?

Use something like
u"".join([unichr(ord(spl[0])*100 + ord(spl[1])-30) for spl in [instr[i: i + 2] for i in range(0, 16, 2)]])
which is a really crummy shift:
1234567890123456 becomes ጸᐂᓌᖖᙖጸᐂᓌ
aAzZ09jdmekfADEF becomes ☇⿤ዛ⦮⫛⨔ᦊᬜ
IamBADatREQUIREM becomes ᳇⪸ᦊ☺ ΊᲸᬣ
zzaa009990123456 becomes 〄☧ዒᙟᙖጸᐂᓌ
which is reversed via:
"".join([chr(ord(num) / 100) + chr(ord(num) % 100 + 30) for num in unistring])
u"〄☧ዒᙟᙖጸᐂᓌ" becomes zzaa009990123456
and thus the circle of life is complete.

If the hash function can return any immutable object, return the strings directly. No need to map them into anything.
def hash(s):
return s
If it needs to return ints, then it's simple. Python integers can be arbitrarily large, so all you have to do is convert the string an int with the same bytes.
def hash(s):
return int.from_bytes(string.encode(), byteorder='big')

hash functions return a string of fixed length relative to the hash function not the input string, what you want is a cipher
https://crypto.stackexchange.com/questions/8765/is-there-a-hash-function-which-has-no-collisions
ASCII value of a character in Python
from random import shuffle
def create_cipher():
key = []
# ASCII value of numerals
for i in range(48,58):
key.append(i)
# ASCII value of lowercase
for i in range(65,91):
key.append(i)
# ASCII value of uppercase
for i in range(97,123):
key.append(i)
print key
cipher = list(key)
shuffle(cipher)
print cipher
cipher_dict = {}
for i in range(len(key)):
cipher_dict[key[i]] = cipher[i]
return cipher_dict
def cipher(string,code_dict):
coded_list = []
list_string = list(string)
list_string = [ord(i) for i in list_string]
for i in list_string:
coded_list.append(code_dict[i])
coded_list = [chr(i) for i in coded_list]
return ''.join(coded_list)
msg = 'HelloWorld2017'
encode_dict = create_cipher()
decode_dict = {y:x for x,y in encode_dict.iteritems()}
encoded_cipher = cipher(msg,encode_dict)
decoded_cipher = cipher(encoded_cipher,decode_dict)
print msg
print encoded_cipher
print decoded_cipher
>>>
HelloWorld2017
pryyLILoyx9fgm
HelloWorld2017
of course you'd want to validate your inputs... for alphanumeric you can use:
isalnum()

Related

Get n Characters from String specified in python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Let s = "%2ABCDE" - get first 2 characters from string
then output should be "AB".
Need to get characters from string specified by numeral in string.
E.g. s1="%12ABCDERTYUIOPLKHGF" - get first 12 characters from string.
I tried to get digit using re.findall('\d+', string ), but this creates problem if my string would be "%2ABCD1".
Please suggest
s = "%2ABCDE"
number = ""
offset = 0
for i in range(len(s)):
if s[i] == "%":
continue
elif s[i].isdigit():
number += s[i]
else:
offset = i
break
print(s[offset:int(number) + offset])
Output: AB
A simpler way of doing this would be to do the following:
txt = "%2ABCDE"
number_list = [s for s in txt if s.isdigit()]
number_concate = int("".join(number_list))
txt_filtered = txt[len(number_list)+1:]
print(txt_filtered[:number_concate])
Outputs AB for string "%2ABCDE"
Outputs ABCDERTYUIOP for string "%12ABCDERTYUIOPLKHGF"
You are taking your string, doing a list comprehension of the string if the digit exists, then joining the list and changing this to an integer to allow for you to filter your string accordingly. Then you strip the string to only the characters and you have your answer printed out.
import re
s = '%2ABCDERTYUIOPLKHGF'
numeral_instruction = re.search(r'%\d+',s).group(0)
start = len(numeral_instruction)
stop = start + int(numeral_instruction[1:])
s[start:stop]
outputs
AB
You can get the position of the first non-digit character in the string (skipping the %) and use that as the basis to get the length and form a substring:
s1="%12ABCDERTYUIOPLKHGF"
i = next(i for i,c in enumerate(s1[1:],1) if not c.isdigit())
result = s1[i:i+int(s1[1:i])]
print(result)
ABCDERTYUIOP
If the first number in the string is not always at index 1, you can skip a variable number of characters using the same technique:
s1="*:%12ABCDERTYUIOPLKHGF"
start = next(i for i,c in enumerate(s1) if c.isdigit())
end = next(i for i,c in enumerate(s1[start:],start) if not c.isdigit())
result = s1[end:end+int(s1[start:end])]
print(result)
ABCDERTYUIOP
If you want to use the re module, you only need the first occurrence of a number, so use re.search() instead of re.findall():
import re
m = re.search(r"\d+",s1)
result = s1[m.end():m.end()+int(m.group())]
print(result)
ABCDERTYUIOP

How to duplicate numbers in string n times? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have this string (61,62,63,64) and i want to tranform the string into (61,61,62,62,62,62,63,64).
I want to duplicate the numbers in the string n times, the 61 i want to duplicate twice, the 62 i want to duplicate four times, how do i code something that duplicates a number in the string n times?
Can you possible do something like have annother string that tells the computer how many times to duplicate each number? (61, 62, 63, 64,) (2,4,1,1)
if both your inputs are strings:
a = '(61, 62, 63, 64,)'
b = '(2,4,1,1)'
a = [i for i in a[1:-1].strip().replace(" ","").split(",")]
a.remove('')
b = [int(i) for i in b[1:-1].strip().replace(" ","").split(",")]
result = "("
for i in range(len(b)):
for j in range(b[i]):
result += a[i]
result += ", "
result = result.strip()[:-1]+")"
print(result)
Here is a possible solution (if rep is a string and not a tuple, you just need to do rep = eval(rep)):
s = "(61,62,63,64)"
rep = (2,4,1,1)
# convert the string to a tuple
t = eval(s)
# compute the result as a tuple
result = tuple(x for i, x in enumerate(t) for _ in range(rep[i]))
# convert the result into a string
result = str(result)
If you want something more compact:
s = "(61,62,63,64)"
rep = (2,4,1,1)
result = str(tuple(x for i, x in enumerate(eval(s)) for _ in range(rep[i])))
Be careful with using eval!! Check this question for more info.

string concatenation in a loop happens to be on the left . Why? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
String concatenation happens to be on the right side, example:
foo = 'Sorting1234'
foo += 'er'
print(foo)
Sorting1234er
But in a loop this happens:
string = 'Sorting1234'
x = ''
for c in string:
if c.islower():
x+=c
if c.isupper():
x+=c
print(x)
Sorting
I would expect the output to be:
ortingS
Since I am 'appending' the lowercase first in the loop and 'appending' the uppercase later.
At the moment, you are processing the letters in the order of the original string, rather than by case. This means that your current for loop has little effect but to prevent the printing of numeric values.
One way to achieve the behaviour you're looking for, with the lower case characters appended first, would be to use two loops: the first looking for lower case characters and the second looking for upper case characters, i.e.:
string = 'Sorting1234'
x = ''
for c in string:
if c.islower():
x += c
for c in string:
if c.isupper():
x += c
print(x)
Output:
ortingS
An alternative way, requiring one pass over the string, could be to store lists of the lower and upper case characters, then join them at the end:
lower, upper = [], []
for c in string:
if c.islower():
lower.append(c)
elif c.isupper():
upper.append(c)
print(''.join(lower + upper))
Output:
ortingS
string = 'Sorting1234'
x = ''
for c in string:
if c.islower():
x+=c
if c.isupper():
x+=c
print(x)
print(x)
x=''
#x += c -> x = x + x -> appends c to the right of x, which it's doing it correctly
When printing the output you can see:
S
So
Sor
Sort
Sorti
Sortin
Sorting
You can see you are simply looping through the string and appending each letter, the if statements are practically useless in your case.

Creating my own string functions [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
def tlower(str1):
list = list(str1)
final = ''
for char in range(0,len(str1)):
if list[char] in UPPERCASE:
for ascii in range(0,len(UPPERCASE)):
if list[char] == UPPERCASE[ascii]:
list[char] = LOWERCASE[ascii]
final += list[char]
return final
NOTE - UPPERCASE and LOWERCASE are strings of all upper/lowercase letters
NOTE - can NOT use any string functions built into python (Replace, etc..)
I have this function to turn any string into all lower case, (Yes i know there is a built in function..) But compared to my other string functions I have created, this is fairly long, any better approach I should take to do doing this?
UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LOWERCASE = "abcdefghijklmnopqrstuvwxyz"
def to_lower(s, trans=dict(zip(UPPERCASE, LOWERCASE))):
return ''.join(trans.get(ch,ch) for ch in s)
print to_lower('This Is a TEST') # => 'this is a test'
Edit:
zip() takes two lists and returns pairs of values, ie
zip('ABC', 'abc') # => [('A','a'), ('B','b'), ('C','c')]
dict() makes a dictionary - in this case,
{'A':'a', 'B':'b', 'C':'c'}
trans.get(x, y) is a more compact way of saying as trans[x] if x in trans else y. In this case, "if you have a lowercase version of this letter, return it, otherwise give back the original letter".
and if you don't like .join, how about reduce?
from operator import add
def to_lower(s, trans=dict(zip(UPPERCASE, LOWERCASE))):
return reduce(add, (trans.get(ch,ch) for ch in s), '')
For completeness:
def to_lower(string):
ords = (ord(c) for c in string)
return ''.join(chr(o + 32 * (65 <= o <= 90)) for o in ords)

How can I write a function that returns the smallest value greater than 0 from a list? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I am looking to identify the smallest value greater than 0 from a list but need some help.
Can anyone provide some example code?
Thanks
Given initial list called values:
values = [...]
result = min(value for value in values if value > 0)
The resulting value is stored in result. Here we use generator expression with filtering instead of list comprehensions for memory savings O(1) memory in this case.
def smallest_value_greater_than_0(numbers):
return min(num for num in numbers if num > 0)
As requested in your comment, if you have a dictionary and want to return both the key and value of the item with the smallest value:
def smallest_value_greater_than_0(numbers):
value, key = min((v, k) for k, v in numbers.iteritems() if v > 0)
return key, value
numbs = dict(A=2, B=3, C=0)
key, value = smallest_value_greater_than_0(numbs) # key="A", value=2
(In Python 3.x, just use numbers.items() instead of numbers.iteritems(). Also note in Python 3 that all the keys should be of the same type.)
Note that if multiple entries have the same value, this will return the one with the lowest key, using Python's sorting order. For example, if A=1, B=3, C=0, D=1, you will get A=1 back, never D=1. If some keys are numbers and others are strings, or some are uppercase and some are lowercase, you may not get the result you expect, though it will be predictable.
You can use a generator:
def smallestPositive(lst):
return min(x for x in lst if x > 0)

Categories