How do I make independent lists within in a list? - python

seats = 4 # user can choose an even input, I put 4 for this example
rows = 4 # user can choose an even or odd input, I put 4 for this example
seats_in_row_list = [i for i in string.ascii_uppercase[:seats]]
main_seat_list = [seats_in_row_list for i in range(rows)]
The output is:
[['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D']]
But when I try to change 'A' to 'X' in the first list all of the lists change:
[['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D'], ['X', 'B', 'C', 'D']]
What I'm looking for is this output:
[['X', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D'], ['A', 'B', 'C', 'D']]

Use copy method to have a copy of the individual list before assigning
main_seat_list = [seats_in_row_list.copy() for i in range(rows)]

If you aren't using seats_in_row_list for anything other than the construction of main_seat_list, you should just inline the definition. Calling list here would be simpler than using a list comprehension.
seats = 4
rows = 4
main_seat_list = [list(string.ascii_uppercase[:seats]) for i in range(rows)]

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']]

how do I input custom arrays into rows & columns in 2d character array

Rows = int(input("give the number of rows:"))
Columns = int(input("Give the number of columns:"))
matrix = []
for i in range(Rows):
matrix.append(['a', 'b', 'c','d', 'e'])
for vector in matrix:
print(matrix)
here's the output:
give the number of rows:3
Give the number of columns:3
[['a', 'b', 'c', 'd', 'e']]
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
[it needed to be like this when the user input the rows and columns 3x3]
a b c
d e f
g h i
There are many ways to initalize an array with a specific size. Below is one of the more concise ways.
Rows = int(input("Give the number of rows:"))
Columns = int(input("Give the number of columns:"))
matrix = [["a"]*Rows]*Columns
print(matrix)
This will give the output
Give the number of rows:3
Give the number of columns:3
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
This gives the array sizing that you are looking for.

Python List Column Move

I'm trying to move the second value in a list to the third value in a list for each nested list. I tried the below, but it's not working as expected.
Code
List = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
print(List)
col_out = [List.pop(1) for col in List]
col_in = [List.insert(2,List) for col in col_out]
print(List)
Result
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']]
[['a', 'b', 'c', 'd'], [...], [...]]
Desired Result
[['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']]
UPDATE
Based upon pynoobs comment, i came up with the following. But i'm still not there. Why is 'c' printing?
Code
List = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
col_out = [col.pop(1) for col in List for i in col]
print(col_out)
Result
['b', 'c', 'b', 'c', 'b', 'c']
[List.insert(2,List) for col in col_out]
^^^^ -- See below.
You are inserting an entire list as an element within the same list. Think recursion!
Also, please refrain from using state-changing expressions in list comprehension. A list comprehension should NOT modify any variables. It is bad manners!
In your case, you'd do:
lists = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
for lst in lists:
lst[1], lst[2] = lst[2], lst[1]
print(lists)
Output:
[['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']]
You can do it like this
myList = [['a','b','c','d'],['a','b','c','d'],['a','b','c','d']]
myOrder = [0,2,1,3]
myList = [[sublist[i] for i in myOrder] for sublist in myList]

Appending a value to start of list

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']]

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