Using Python I want to randomly rearrange sections of a string based on a given key. I also want to restore the original string with the same key:
def rearrange(key, data):
pass
def restore(key, rearranged_data):
pass
Efficiency is not important. Any ideas?
Edit:
can assume key is hashable, but may be multiple types
definition of section for ignacio
Use random.shuffle with the key as a seed:
import random
def rearrange(key, data):
random.seed(key)
d = list(data)
random.shuffle(d)
return ''.join(d)
def restore(key, rearranged_data):
l = len(rearranged_data)
random.seed(key)
d = range(l)
random.shuffle(d)
s = [None] * l
for i in range(l):
s[d[i]] = rearranged_data[i]
return ''.join(s)
x = rearrange(42, 'Hello, world!')
print x
print restore(42, x)
Output:
oelwrd!, llHo
Hello, world!
you can reinvent the wheel, but why not try an encryption library first, if possible.
An implementation that reverses the shuffling with sort():
import random
def reorder_list(ls, key):
random.seed(key)
random.shuffle(ls)
def reorder(s, key):
data = list(s)
reorder_list(data, key)
return ''.join(data)
def restore(s, key):
indexes = range(len(s))
reorder_list(indexes, key)
restored = sorted(zip(indexes, list(s)))
return ''.join(c for _, c in restored)
Related
I've been struggling in creating the vigenere table in python
That should be the result:
So basically I have the entire alphabet on the first line, and the alphabet shifted by one letter on the second one etc.
That's my code so far:
class CypherTable:
def __init__(self):
self.matrix = [[chr(i) for i in range(ord('a'),ord('z')+1)] for i in range(5)]
def __str__(self):
for i in range(len(self.matrix)):
print self.matrix[i]
return ""
table = CypherTable()
print(table)
I managed to print letters from a to z a number of times but I don't know how to modify each interaction in order to shift the first letter by one.
I'm used to work in java where you first define the array length and then populate it, but since python has a faster syntax I can't figure out what's the best way to do it.
A simpler way is to use the string module:
from string import ascii_uppercase as l
class CypherTable:
def __init__(self):
self.final_table = [l[i:]+l[:i] for i in range(len(l))]
for i in CypherTable().final_table:
print(i)
Output:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY
To be even cleaner, particularly if you will not be declaring any other methods in the class, you can use #classmethod:
from string import ascii_uppercase as l
class CypherTable:
final_table = [l[i:]+l[:i] for i in range(len(l))]
#classmethod
def show_board(cls):
for i in cls.final_table:
print(i)
CypherTable.show_board()
Regarding your recent comment, you can try this:
from string import ascii_uppercase as l
class CypherTable:
def __init__(self):
self.final_table = [l[i:]+l[:i] for i in range(len(l))]
def cross(self, b, a):
val1 = self.final_table[0].index(a)
new_letter = [i for i in self.final_table if i[0] == b][0][val1]
return new_letter
c = CypherTable()
print(c.cross('P', 'C'))
Output:
'R'
Here's your code with a minimum amount of changes. You can use modulo to loop from 26 back to 0. Note that __str__ should return a string and shouldn't print anything:
class CypherTable:
def __init__(self):
self.matrix = [[chr(ord('A') + (i + j) % 26) for i in range(26)] for j in range(5)]
def __str__(self):
return "\n".join('|'.join(row) for row in self.matrix)
table = CypherTable()
print(table)
It outputs:
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
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
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
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
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
Basically, I have a bunch of numpy arrays each with a list of websites in a larger array. I wanted to, with input from the user, basically return the arrays where the input of the user is the first element of the array. It would return that, the user would input another website, and it would be the second element of the arrays that matched the first time. So for example:
bigarray = [['website1','website2', 'website3', 'website4'],
['website1', 'website7', 'website9', 'website3'],
['website1','website2','website5', 'website9','website24','website36']]
basically if someone were to input 'website1' it would return
{'website2':2, 'website7':1}
after if they were to input website 2 it would output
{'website3':1,"website5":1}
and so on. I hope I was clear, if not, please comment and I'll make it more clear. I don't know how to make this efficient and quick, I've been brainstorming but I can only come up with inefficient methods. Please help,
This is what I have so far, but it doesn't do a dictionary with frequencies. I can't figure out how to get frequencies in the dictionary, nor can I figure out how to get the second third fourth etc. elements searching. This only works for the first element.
import numpy as np
import cherrypy as cp
def initialize(self):
pagearray = np.load("pagearray.npy")
def submit(self, input):
for i in pagearray:
if input==i[0]:
subpagearray += [i[1:]]
possibilities +=i[0]
return possibilities
Thanks,
F
You could use a data structure that solves better your problem. Here you can find some options in Python. Try to avoid premature optimization, and keep your code simpler as you can.
Figured it out... this is what I was going for:
import numpy as np
import simplejson as json
import cherrypy as cp
import operator
global pagearray
def initialize(self):
global pagearray
pagearray = np.load("pagearray.npy")
#return os.path
def getUserPath(self, input):
subpagearray = []
possibilities = []
global pagearray
for i in pagearray:
try:
if input==i[0]:
subpagearray += [i[1:]]
possibilities+= [i[1]]
except IndexError:
pass
x = build_dict(possibilities)
sorted_x = sorted(x.items(), key=operator.itemgetter(1), reverse=True)
pagearray = subpagearray
totalelements = len(pagearray)
returnvaluelist = []
weight = []
for i in sorted_x:
returnvaluelist += [i[0]]
weight += [(i[1]/(totalelements*1.0))*100]
return returnvaluelist, weight
def build_dict(a_list=None):
if a_list is None:
a_list = []
site_dict = {}
for site in a_list:
try:
site_dict[site] = site_dict[site] + 1
except KeyError:
site_dict[site] = 1
return site_dict
def build_dict(a_list=None):
if a_list is None:
a_list = []
site_dict = {}
for site in a_list:
try:
site_dict[site] = site_dict[site] + 1
except KeyError:
site_dict[site] = 1
return site_dict
This is how you make a dictionary but I'm not sure what you're going for so you can use this as a template
I figured out what you're going for, I think. Let me know if this is it:
def advanced_dict(a_list=None):
if a_list is None:
a_list = []
index_holder = 0 # Holds the primary dict value
site_dict = {} # contains a dict of dicts
for sub_arr in big_array:
for site in sub_arr:
try:
site_dict['website'+str(index_holder)]
except KeyError:
site_dict['website'+str(index_holder)] = {} # if no dict create dict
try:
site_dict['website'+str(index_holder)][site] += 1
except KeyError:
site_dict['website'+str(index_holder)][site] = 1
index_holder += 1
index_holder = 0
return site_dict
I am understanding the following code to find if the strings are isomorphic or not. The code uses two hashes s_dict and t_dict respectively. I am assuming the strings are of same length.
def isIsomorphic(s, t):
s_dict = {}
t_dict = {}
for i in range(len(s)):
if s[i] in s_dict.keys() and s_dict[s[i]] != t[i]:
return False
if t[i] in t_dict.keys() and t_dict[t[i]] != s[i]:
return False
s_dict[s[i]] = t[i]
t_dict[t[i]] = s[i]
return True
Now, if I modify the above code such that only one hash s_dict() is used, then also it gives desired results to my limited test cases. The modified code is as follows:
def isIsomorphic(s, t):
s_dict = {}
for i in range(len(s)):
if s[i] in s_dict.keys() and s_dict[s[i]] != t[i]:
return False
s_dict[s[i]] = t[i]
return True
What are the test cases in which the above modified code will fail? Is my understanding of the isomorphic strings wrong?
One simple example, your code doesn't work on s='ab',t='aa'.
Basically you have to have both way to be isomorphic. Your code only checked that t can be modified from s, but not the other way around.
This was kind of fun to look at. Just for kicks, here's my solution using itertools.groupby
from itertools import groupby
from collections import defaultdict
def get_idx_count(word):
"""Turns a word into a series of tuples (idx, consecutive_chars)
"aabbccaa" -> [[(0, 2), (3, 2)], [(1, 2)], [(2, 2)]]
"""
lst = defaultdict(list)
for idx, (grp, val) in enumerate(groupby(word)):
lst[grp].append((idx, sum(1 for _ in val)))
return sorted(list(lst.values()))
def is_isomorphic(a, b):
return get_idx_count(a) == get_idx_count(b)
is_isomorphic('aabbcc', 'bbddcc') # True
is_isomorphic('aabbaa', 'bbddcc') # False
Rather than building the lists, I feel like I could do something more like:
from itertools import groupby
from collections import defaultdict
def is_isomorphic(a, b):
a_idxs, b_idxs = defaultdict(set), defaultdict(set)
for idx, ((a_grp, a_vals), (b_grp, b_vals)) in enumerate(zip(groupby(a), groupby(b))):
if sum(1 for _ in a_vals) != sum(1 for _ in b_vals):
return False
# ensure sequence is of same length
if a_grp in a_idxs and b_idxs[b_grp] != a_idxs[a_grp] or\
b_grp in b_idxs and a_idxs[a_grp] != b_idxs[b_grp]:
return False
# ensure previous occurrences are matching groups
a_idxs[a_grp].add(idx)
b_idxs[b_grp].add(idx)
# save indexes for future checks
return True
But I haven't had a chance to test that whatsoever. It does, however, have the likelihood of exiting early, rather than having to build all the lists and comparing them at the end. It also skips a few sets of sorting that shouldn't be necessary anyway, except that we're pulling from dicts, so bleh. Pretty sure list.sort is faster than saving to to a collections.OrderedDict. I think.
Here is a solution for Isomorphic String problem in Python:
Solution #1 (the fastest one):
def isometric_strings_translate(str1: str, str2: str) -> bool:
trans = str.maketrans(str1, str2)
return str1.translate(trans) == str2
Solution #2 (using set):
def isometric_strings_set(str1: str, str2: str) -> bool:
return len(set(zip(str1, str2))) == len(set(str1))
Solution #3 (using dictionary):
def isometric_strings_dict(str1: str, str2: str) -> bool:
map = {}
for s1, s2 in zip(str1, str2):
if map.setdefault(s1, s2) != s2:
return False
return True
Here you can view full code.
Thinking about it without maps or dictionaries can help you understand:
def isIso(x,y):
if len(x) != len(y):
return False
for i in range(len(x)):
count = 0
if x.count(x[i]) != y.count(y[i]):
return False
return True
I have a list with a few hundred of objects, and I want to check, if a newcomer object is already added to my list (not an equal object, but exactly this exact instance).
I have a dumb realization like this:
def is_one_of(test_object, all_objects):
for elm in all_objects:
if test_object is elm:
return True
return False
Cannot it be more beautiful?
use any:
if any(x is test_object for x in all_objects):
The example in the python reference looks remarkably similar to your code already :)
Use the any() function:
def is_one_of(test_object, all_objects):
return any(test_object is elm for elm in all_objects)
It'll stop iterating over the generator expression as soon as a True result is found.
Eh, I made it by putting id(element) to a set:
def _unit_list(self):
"""
Returns all units in the order they should be initialized.
(Performs search by width from start_point).
"""
unit_id_set = set()
unit_list = []
unit_id_set.add(self.start_point)
unit_list.append(self.start_point)
pos = 0
while pos < len(unit_list):
cur_unit = unit_list[pos]
for child in cur_unit.links_to:
if not (id(child) in unit_id_set):
unit_list.append(child)
unit_id_set.add(id(child))
pos += 1
return unit_list
You can use
if any(test_object is x for x in all_objects): ...
if you need to do this test often however may be you can keep a set of all object ids instead
all_ids = set(map(id, all_objects))
then you can check faster with
if id(test_object) in all_ids: ...
Another common solution that may apply is to store in the object itself in a specific field if it has been already processed:
# add the object to the list
all_objects.append(x)
x.added = True
...
# Check if already added
if test_object.added: ...
I think you're looking for the in operator. The equivalent function would be:
def is_one_of(test_object, all_objects):
return test_object in all_objects
(but you really wouldn't want to write that as a function).
Edit: I'm wrong. According to the Expressions page:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
That would work if your class doesn't define __eq__, but that's more fragile than I'd want to rely on. For example:
class ObjWithEq(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
a = ObjWithEq(1)
b = ObjWithEq(1)
assert a == b
assert a in [b]
class ObjWithoutEq(object):
def __init__(self, val):
self.val = val
a = ObjWithoutEq(1)
b = ObjWithoutEq(1)
assert a != b
assert a not in [b]
This question already has answers here:
is there a way to capture misses on a list comprehension?
(6 answers)
Closed 10 years ago.
Basically what I want to do is take two lists of objects and based on some test and divide them into two lists depending on whether the result is True or False. Sort of what filter() does, except that instead of determining if it's in or out it determines which list/iterator to go to. I've made this attempt using itertools.groupby():
import random
from itertools import groupby
class FooObject(object):
def __init__(self):
self.key = random.choice((True, False))
def __repr__(self):
return '<Foo: %s>' % self.key
foos = [FooObject() for _ in range(10)]
left, right = [], []
groups = groupby(sorted(foos, key=lambda o: o.key), lambda o: o.key)
for k, group in groups:
if k:
right = list(group)
else:
left = list(group)
print left
print right
This gets the job done, but just wondering if there is a clearner/simpler way. I realize I could use filter() (or the equivalent list comprehension) and do it in two passes, but what fun is that?
If you only have 2 buckets, you can use a ternary:
d={'left':[],'right':[]}
for e in (random.random() for i in xrange(50)):
d['left' if e<0.5 else 'right'].append(e)
With more than 2 buckets, use a function that returns keys already defined or use a default dict with a list:
def f(i):
return int(i*10)
DoL=defaultdict(list)
for e in (random.random() for i in xrange(50)):
DoL[f(e)].append(e)
Here's a function that consumes the source only once and returns an dictionary-like object, each member of which is a generator, that yields values from the source as lazily as possible:
def partition(it, fun):
class x(object):
def __init__(self):
self.buf = {}
def flush(self, val):
for p in self.buf.get(val, []):
yield p
self.buf.pop(val, None)
def __getitem__(self, val):
for p in self.flush(val): yield p
while True:
try:
p = next(it)
except StopIteration:
break
v = fun(p)
if v == val:
yield p
else:
self.buf.setdefault(v, []).append(p)
for p in self.flush(val): yield p
return x()
Example of use:
def primes(): # note that this is an endless generator
yield 2
p, n = [], 3
while True:
if all(n % x for x in p):
p.append(n)
yield n
n += 2
p = partition(primes(), lambda x: x % 3)
# each member of p is endless as well
for x in p[1]:
print x
if x > 200: break
for x in p[2]:
print x
if x > 200: break