Appending a value to start of list - python

Currently working on a 2D transposition cipher in Python. So I have a list that contains an encoded message, like below:
['BF', 'AF', 'AF', 'DA', 'CD', 'DD', 'BC', 'EF', 'DA', 'AA', 'EF', 'BF']
The next step is taking that list, splitting it up and putting it into a new matrix with regards to a keyword that the user enters. Which I have below:
Enter the keyword for final encryption: hide
H I D E
['B', 'F', 'A', 'F']
['A', 'F', 'D', 'A']
['C', 'D', 'D', 'D']
['B', 'C', 'E', 'F']
['D', 'A', 'A', 'A']
['E', 'F', 'B', 'F']
What I would like to do next and haven't done is take each of the columns above and print them in alphabetical order, therefore getting another cipher text, like below:
D E H I
['A', 'F', 'B', 'F']
['D', 'A', 'A', 'F']
['D', 'D', 'C', 'D']
['E', 'F', 'B', 'C']
['A', 'A', 'D', 'A']
['B', 'F', 'E', 'F']
Here's my code:
def encodeFinalCipher():
matrix2 = []
# Convert keyword to upper case
keywordKey = list(keyword.upper())
# Convert firstEncryption to a string
firstEncryptionString = ''.join(str(x) for x in firstEncryption)
# Print the first table that will show the firstEncryption and the keyword above it
keywordList = list(firstEncryptionString)
for x in range(0,len(keywordList),len(keyword)):
matrix2.append(list(keywordList[x:x+len(keyword)]))
# Print the matrix to the screen
print (' %s' % ' '.join(map(str, keywordKey)))
for letters in matrix2:
print (letters)
return finalEncryption
I have traversed the 2D matrix and got all the column entries like below:
b = [[matrix2[i][j] for i in range(len(matrix2))] for j in range(len(matrix2[0]))]
for index, item in enumerate (b):
print("\n",index, item)
OUTPUT:------
0 ['B', 'A', 'C', 'B', 'D', 'E']
1 ['F', 'F', 'D', 'C', 'A', 'F']
2 ['A', 'D', 'D', 'E', 'A', 'B']
3 ['F', 'A', 'D', 'F', 'A', 'F']
How would I append each letter of the keywordKey (e.g. 'H' 'I' 'D' 'E') to the list where the numbers 0,1,2,3 are?
Or probably a more efficient solution. How would I put the letters into the keywordKey columns when creating the matrix? Would a dictionary help here? Then I could sort the dictionary and print the final cipher.
Many thanks

You can do something like this:
>>> from operator import itemgetter
>>> from pprint import pprint
>>> lst = [['B', 'F', 'A', 'F'],
['A', 'F', 'D', 'A'],
['C', 'D', 'D', 'D'],
['B', 'C', 'E', 'F'],
['D', 'A', 'A', 'A'],
['E', 'F', 'B', 'F']]
>>> key = 'HIDE'
Sort xrange(len(key)) or range(len(key)) using the corresponding values from key and then you will have a list of indices:
>>> indices = sorted(xrange(len(key)), key=key.__getitem__)
>>> indices
[2, 3, 0, 1]
Now all we need to do is loop over the list and apply these indices to each item using operator.itemgetter and get the corresponding items:
>>> pprint([list(itemgetter(*indices)(x)) for x in lst])
[['A', 'F', 'B', 'F'],
['D', 'A', 'A', 'F'],
['D', 'D', 'C', 'D'],
['E', 'F', 'B', 'C'],
['A', 'A', 'D', 'A'],
['B', 'F', 'E', 'F']]
#or simply
>>> pprint([[x[i] for i in indices] for x in lst])
[['A', 'F', 'B', 'F'],
['D', 'A', 'A', 'F'],
['D', 'D', 'C', 'D'],
['E', 'F', 'B', 'C'],
['A', 'A', 'D', 'A'],
['B', 'F', 'E', 'F']]

Related

Is it possible to add lists inside a list?

I created 2 lists in python `
ls = []
a = ['a','b','c','d','e','f']
i = 0
while i < 5:
x = a[-1]
a.pop(-1)
a.insert(0, x)
ls.insert(0, a)
i += 1
print(ls)
What I want to do is to add something from the list filled with letters into an empty list and making the result look like this
ls = [
['a','b','c','d','e','f'],
['f','a','b','c','d','e'],
['e','f','a','b','c','d'],
['d','e','f','a','b','c'],
['c','d','e','f','a','b'],
['b','c','d','e','f','a']
]
I would like to know where I made a mistake in python and the solution.
The list is a mutable object in python, so when you insert the list a in the ls, you are just adding a reference to the list a, instead of adding the whole value.
A workaround would be to insert a copy of a in the ls. One way to create a new copy of the list is using the list() on the list or you can use copy function from copy module. So doing ls.insert(0, a.copy()) would give the same result as below -
ls = []
a = ['a','b','c','d','e','f']
i = 0
while i < 5:
x = a[-1]
a.pop(-1)
a.insert(0, x)
ls.insert(0, list(a)) # updated this
i += 1
print(ls)
Output:
[['b', 'c', 'd', 'e', 'f', 'a'], ['c', 'd', 'e', 'f', 'a', 'b'], ['d', 'e', 'f', 'a', 'b', 'c'], ['e', 'f', 'a', 'b', 'c', 'd'], ['f', 'a', 'b', 'c', 'd', 'e']]
Another easy way to get your expected output would be to -
ls = []
a = ['a','b','c','d','e','f']
for i in range(6):
ls.append(a.copy())
a = [a[-1]] + a[:-1]
print(ls)
Output :
[['a', 'b', 'c', 'd', 'e', 'f'], ['f', 'a', 'b', 'c', 'd', 'e'], ['e', 'f', 'a', 'b', 'c', 'd'], ['d', 'e', 'f', 'a', 'b', 'c'], ['c', 'd', 'e', 'f', 'a', 'b'], ['b', 'c', 'd', 'e', 'f', 'a']]

Product of lists of lists with variable members

Say I have this input data
my_input_list = [[A],[A,B,C],[D],[D,E,F],[A,B,C,D,E,F],[A,C,E]]
items_that_appear_twice = [A,B,C]
items_that_appear_four = [D,E,F]
And I want to create an expansion such that some elements are only allowed to appear twice.
my_output_list = [
[A],[A],
[A,B,C],[A,B,C],
[D],[D],[D],[D],
[D,E,F],[D,E,F],[D,E,F],[D,E,F],
[A,B,C,D,E,F],[A,B,C,D,E,F],[D,E,F],[D,E,F],
[A,C,E],[A,C,E],[E],[E]]
I tired a few ideas and didn't find a really neat solution, like building lists of four and list.remove() from them which generated two empty lists.
For example list removal techniques on my_input_list[0]*4 gives [A],[A],[],[] (two empty lists) when I want [A],[A] .
I have a working version: See Pyfiddle.
my_input_list = [['A'],['A','B','C'],['D'],['D','E','F'],['A','B','C','D','E','F'],['A','C','E']]
items_that_appear_twice = ['A','B','C']
items_that_appear_four = ['D','E','F']
my_output_list = []
for my_input in my_input_list:
items_allowed_to_appear_twice = list(filter(
lambda value: (value in items_that_appear_twice
or value in items_that_appear_four),
my_input))
items_allowed_to_appear_four = list(filter(
lambda value: value in items_that_appear_four,
my_input))
my_output_list += 2*[items_allowed_to_appear_twice]
if len(items_allowed_to_appear_four):
my_output_list += 2*[items_allowed_to_appear_four]
print(my_output_list)
my_input_list = [['A'],
['A', 'B', 'C'],
['D'],
['D', 'E', 'F'],
['A', 'B', 'C', 'D', 'E', 'F'],
['A', 'C', 'E']]
items_that_appear_twice = ['A', 'B', 'C']
items_that_appear_four = ['D', 'E', 'F']
my_output_list = []
for sub in my_input_list:
my_output_list.append(sub)
my_output_list.append(sub)
sub = [x for x in sub if x in items_that_appear_four]
if sub:
my_output_list.append(sub)
my_output_list.append(sub)
assert my_output_list == [
['A'], ['A'],
['A', 'B', 'C'], ['A', 'B', 'C'],
['D'], ['D'], ['D'], ['D'],
['D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F'],
['A', 'B', 'C', 'D', 'E', 'F'], ['A', 'B', 'C', 'D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F'],
['A', 'C', 'E'], ['A', 'C', 'E'], ['E'], ['E']]
Below is my solution, sort the sub list first, then append to the result according different situation.
my_input_list = [['A'],['A','B','C'],['D'],['D','E','F'],['A','B','C','D','E','F'],['A','C','E']]
items_that_appear_twice = ['A','B','C']
items_that_appear_four = ['D','E','F']
result = []
for sublist in my_input_list:
appearence = {1:[], 2:[], 4:[]}
for item in sublist:
appearence[2].append(item) if item in items_that_appear_twice else (appearence[4].append(item) if item in items_that_appear_four else appearence[1].append(item))
if len(appearence[2]) > 0:
result.append([appearence[2] + appearence[4]] * 2 + ([appearence[4]] * 2 if appearence[4] and len(appearence[4]) > 0 else []))
else:
result.append([appearence[4]] * 4)
for item in result:
print(item)
output:
[['A'], ['A']]
[['A', 'B', 'C'], ['A', 'B', 'C']]
[['D'], ['D'], ['D'], ['D']]
[['D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F']]
[['A', 'B', 'C', 'D', 'E', 'F'], ['A', 'B', 'C', 'D', 'E', 'F'], ['D', 'E', 'F'], ['D', 'E', 'F']]
[['A', 'C', 'E'], ['A', 'C', 'E'], ['E'], ['E']]
[Finished in 0.178s]

Is there a pythonic way of permuting a list of list?

I have a list of lists containing unique strings and I want to produce an arbitrary number of different ways of sorting it. The list might look like the following:
list = [[a], [b,c], [d], [e,f,g]]
The order of the lists need to be the same but I want to shuffle the ordering within a list and then have them in a single list, e.g
list1 = [a,b,c,d,e,f,g]
list2 = [a,c,b,d,f,e,g]
...
...
listN = [a,c,b,d,f,g,e]
What is a good pythonic way of achieving this? I'm on python 2.7.
from itertools import permutations, product
L = [['a'], ['b','c'], ['d'], ['e', 'f', 'g']]
for l in product(*map(lambda l: permutations(l), L)):
print([item for s in l for item in s])
produces:
['a', 'b', 'c', 'd', 'e', 'f', 'g']
['a', 'b', 'c', 'd', 'e', 'g', 'f']
['a', 'b', 'c', 'd', 'f', 'e', 'g']
['a', 'b', 'c', 'd', 'f', 'g', 'e']
['a', 'b', 'c', 'd', 'g', 'e', 'f']
['a', 'b', 'c', 'd', 'g', 'f', 'e']
['a', 'c', 'b', 'd', 'e', 'f', 'g']
['a', 'c', 'b', 'd', 'e', 'g', 'f']
['a', 'c', 'b', 'd', 'f', 'e', 'g']
['a', 'c', 'b', 'd', 'f', 'g', 'e']
['a', 'c', 'b', 'd', 'g', 'e', 'f']
['a', 'c', 'b', 'd', 'g', 'f', 'e']
You can do this by taking the Cartesian product of the permutations of the sub-lists, and then flattening the resulting nested tuples.
from itertools import permutations, product, chain
lst = [['a'], ['b', 'c'], ['d'], ['e', 'f', 'g']]
for t in product(*[permutations(u) for u in lst]):
print([*chain.from_iterable(t)])
output
['a', 'b', 'c', 'd', 'e', 'f', 'g']
['a', 'b', 'c', 'd', 'e', 'g', 'f']
['a', 'b', 'c', 'd', 'f', 'e', 'g']
['a', 'b', 'c', 'd', 'f', 'g', 'e']
['a', 'b', 'c', 'd', 'g', 'e', 'f']
['a', 'b', 'c', 'd', 'g', 'f', 'e']
['a', 'c', 'b', 'd', 'e', 'f', 'g']
['a', 'c', 'b', 'd', 'e', 'g', 'f']
['a', 'c', 'b', 'd', 'f', 'e', 'g']
['a', 'c', 'b', 'd', 'f', 'g', 'e']
['a', 'c', 'b', 'd', 'g', 'e', 'f']
['a', 'c', 'b', 'd', 'g', 'f', 'e']
If you need to do this in Python 2, you can replace the print line with this:
print list(chain.from_iterable(t))
Here's a more compact version, inspired by ewcz's answer:
for t in product(*map(permutations, lst)):
print list(chain.from_iterable(t))
This might not be the most elegant solution, but I think it does what you want
from itertools import permutations
import numpy as np
def fac(n):
if n<=1:
return 1
else:
return n * fac(n-1)
lists = [['a'], ['b','c'], ['d'], ['e','f','g']]
combined = [[]]
for perm in [permutations(l,r=len(l)) for l in lists]:
expanded = []
for e in list(perm):
expanded += [list(l) + list(e) for l in combined]
combined = expanded
## check length
print np.prod(map(fac,map(len,lists))), len(combined)
print '\n'.join(map(str,combined))
You can flatten the list then simply generate its permutations:
from itertools import chain, permutations
li = [['a'], ['b','c'], ['d'], ['e','f','g']]
flattened = list(chain.from_iterable(li))
for perm in permutations(flattened, r=len(flattened)):
print(perm)
>> ('a', 'b', 'c', 'd', 'e', 'f', 'g')
('a', 'b', 'c', 'd', 'e', 'g', 'f')
('a', 'b', 'c', 'd', 'f', 'e', 'g')
('a', 'b', 'c', 'd', 'f', 'g', 'e')
('a', 'b', 'c', 'd', 'g', 'e', 'f')
('a', 'b', 'c', 'd', 'g', 'f', 'e')
('a', 'b', 'c', 'e', 'd', 'f', 'g')
('a', 'b', 'c', 'e', 'd', 'g', 'f')
('a', 'b', 'c', 'e', 'f', 'd', 'g')
...
...
...
from itertools import chain, permutations
your_list = [[a], [b,c], [d], [e,f,g]]
flattened = chain.from_iterable(your_list)
perms = permutations(flattened)
for perm in perms:
print perm
References:
permutations in Python 2
chain in Python 2

Sorting a list by a key

Currently working on a transposition problem. What I have so far is that a user enters a message and that message is encrypted into a list, like below:
['BC', 'DE', 'DE', 'DA', 'FD', 'DD', 'BE', 'FE', 'DA', 'EA', 'FE', 'BC']
What I have for the next stage of the cipher is putting this into a table with a key inputted from the user. So if the user enters 'CODE' it outputs this:
2: Enter the keyword for final encryption: code
C O D E
['B', 'C', 'D', 'E']
['D', 'E', 'D', 'A']
['F', 'D', 'D', 'D']
['B', 'E', 'F', 'E']
['D', 'A', 'E', 'A']
['F', 'E', 'B', 'C']
The next stage is to take each value of each column and print the values corresponding to its alphabetical column. So my expected output would be:
C D E O
['B', 'D', 'E', 'C']
['D', 'D', 'A', 'E']
['F', 'D', 'D', 'D']
['B', 'F', 'E', 'E']
['D', 'E', 'A', 'A']
['F', 'B', 'C', 'E']
The problem I'm having is trying to know how to put each of the values in their corresponding column and printing them.
Here's what I have so far:
def encodeFinalCipher():
matrix2 = []
# Convert keyword to upper case
key = list(keyword.upper())
# Convert firstEncryption to a string
firstEncryptionString = ''.join(str(x) for x in firstEncryption)
# Print the first table that will show the firstEncryption and the keyword above it
keywordList = list(firstEncryptionString)
for x in range(0,len(keywordList),len(keyword)):
matrix2.append(list(keywordList[x:x+len(keyword)]))
# Print the un-ordered matrix to the screen
print (' %s' % ' '.join(map(str, key)))
for letters in matrix2:
print (letters)
unOrderedMatrix = [[matrix2[i][j] for i in range(len(matrix2))] for j in range(len(matrix2[0]))]
for index, item in enumerate (unOrderedMatrix):
print("\n",index, item)
index = sorted(key)
print(index)
I get the output of the sorted key:
['A', 'K', 'M', 'R']
What I would like to know is how can this sorted key be applied to the values they represent? I know I can get the first column by doing this:
print(unOrderedMatrix[0])
Which gets me the list of the first column.
Any help would be much appreciated. Complete beginner on Python
msg = ['BC', 'DE', 'DE', 'DA', 'FD', 'DD', 'BE', 'FE', 'DA', 'EA', 'FE', 'BC', '12']
key = 'CODE'
# 'flatten' the message
msg = ''.join(msg)
key_length = len(key)
#create a dictionary with the letters of the key as the keys
#use a slice to create the values
columns = {k:msg[i::key_length] for i, k in enumerate(key)}
print columns
# sort the columns on the key letters
columns = sorted(columns.items())
print columns
# separate the key from the columnar data
header, data = zip(*columns)
print header
# transpose and print
for thing in zip(*data):
print thing
>>>
{'C': 'BDFBDF1', 'E': 'EADEAC', 'D': 'DDDFEB', 'O': 'CEDEAE2'}
[('C', 'BDFBDF1'), ('D', 'DDDFEB'), ('E', 'EADEAC'), ('O', 'CEDEAE2')]
('C', 'D', 'E', 'O')
('B', 'D', 'E', 'C')
('D', 'D', 'A', 'E')
('F', 'D', 'D', 'D')
('B', 'F', 'E', 'E')
('D', 'E', 'A', 'A')
('F', 'B', 'C', 'E')
>>>
code = raw_input("Enter the keyword for final encryption:")
user_input = ['BC', 'DE', 'DE', 'DA', 'FD', 'DD', 'BE', 'FE', 'DA', 'EA', 'FE', 'BC']
user_input = ''.join(user_input)
matrix = [user_input[i:i+len(code)] for i in range(0, len(user_input), len(code))]
matrix.insert(0, code)
result = sorted([[matrix[j][ind] for j in range(len(matrix))] for ind in range(len(code)) ], key= lambda i:i[0])
for row in [[each[ind] for each in result] for ind in range(len(result[0]))]:
print row
Print row results as:
Enter the keyword for final encryption:CODE
['C', 'D', 'E', 'O']
['B', 'D', 'E', 'C']
['D', 'D', 'A', 'E']
['F', 'D', 'D', 'D']
['B', 'F', 'E', 'E']
['D', 'E', 'A', 'A']
['F', 'B', 'C', 'E']
Here is something to get you started (you may want to separate the loop one-liner to smaller bits):
# define data
data = [['B', 'C', 'D', 'E'], ['D', 'E', 'D', 'A'], ['F', 'D', 'D', 'D'], ['B', 'E', 'F', 'E'], ['D', 'A', 'E', 'A'], ['F', 'E', 'B', 'C']]
# choose code word
code = 'code'
# add original locations to code word [(0, c), (1, o), (2, d), (3, e))]
# and sort them alphabetically!
code_with_locations = list(sorted(enumerate(code)))
print code_with_locations # [(0, 'c'), (2, 'd'), (3, 'e'), (1, 'o')]
# re-organize data according to new indexing
for index in range(len(data)):
# check if code is shorter than list in current index,
# or the other way around, don't exceed either list
max_substitutions = min(map(len, [code_with_locations, data[index]]))
# create a new list according to new indices
new_list = []
for i in range(max_substitutions):
current_index = code_with_locations[i][0]
new_list.append(data[index][current_index])
# replace old list with new list
data[index] = new_list
print data
Output for 'code' would be:
[['B', 'D', 'E', 'C'],
['D', 'D', 'A', 'E'],
['F', 'D', 'D', 'D'],
['B', 'F', 'E', 'E'],
['D', 'E', 'A', 'A'],
['F', 'B', 'C', 'E']]
With help from itertools
from pprint import pprint
from itertools import chain, izip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
z = ['BC', 'DE', 'DE', 'DA', 'FD', 'DD', 'BE', 'FE', 'DA', 'EA', 'FE', 'BC']
input = 'CODE'
pprint([[b for (a, b) in sorted(zip(input, x))]
for x in grouper(chain.from_iterable(z), len(input))])
[['B', 'D', 'E', 'C'],
['D', 'D', 'A', 'E'],
['F', 'D', 'D', 'D'],
['B', 'F', 'E', 'E'],
['D', 'E', 'A', 'A'],
['F', 'B', 'C', 'E']]

Iteratively collect first two elements of each vector of a matrix

I have a matrix:
matrix = [['F', 'B', 'F', 'A', 'C', 'F'],
['D', 'E', 'B', 'E', 'B', 'E'],
['F', 'A', 'D', 'B', 'F', 'B'],
['B', 'E', 'F', 'B', 'D', 'D']]
I want to remove and collect the first two elements of each sub-list, and add them to a new list.
so far i have got:
while messagecypher:
for vector in messagecypher:
final.extend(vector[:2])
the problem is; the slice doesn't seem to remove the elements, and I end up with a huge list of repeated chars. I could use .pop(0) twice, but that isn't very clean.
NOTE: the reason i remove the elements is becuase i need to keep going over each vector until the matrix is empty
You can keep your slice and do:
final = []
for i in range(len(matrix)):
matrix[i], final = matrix[i][:2], final + matrix[i][2:]
Note that this simultaneously assigns the sliced list back to matrix and adds the sliced-off part to final.
Well you can use a list comprehension to get the thing done, but its perhaps counter-intuitive:
>>> matrix = [['F', 'B', 'F', 'A', 'C', 'F'],
['D', 'E', 'B', 'E', 'B', 'E'],
['F', 'A', 'D', 'B', 'F', 'B'],
['B', 'E', 'F', 'B', 'D', 'D']]
>>> while [] not in matrix: print([i for var in matrix for i in [var.pop(0), var.pop(0)]])
['F', 'B', 'D', 'E', 'F', 'A', 'B', 'E']
['F', 'A', 'B', 'E', 'D', 'B', 'F', 'B']
['C', 'F', 'B', 'E', 'F', 'B', 'D', 'D']
EDIT:
Using range makes the syntax look cleaner:
>>> matrix = [['C', 'B', 'B', 'D', 'F', 'B'], ['D', 'B', 'B', 'A', 'B', 'A'], ['B', 'D', 'E', 'F', 'C', 'B'], ['B', 'A', 'C', 'B', 'E', 'F']]
>>> while [] not in matrix: print([var.pop(0) for var in matrix for i in range(2)])
['C', 'B', 'D', 'B', 'B', 'D', 'B', 'A']
['B', 'D', 'B', 'A', 'E', 'F', 'C', 'B']
['F', 'B', 'B', 'A', 'C', 'B', 'E', 'F']
Deleting elements is not an efficient way to go about your task. It requires Python to perform a lot of unnecessary work shifting things around to fill the holes left by the deleted elements. Instead, just shift your slice over by two places each time through the loop:
final = []
for i in xrange(0, len(messagecypher[0]), 2):
for vector in messagecypher:
final.extend(vector[i:i+2])

Categories