Use global positions to mutate list, in list of lists - python

I need to keep my data in a list of lists, but want to edit elements in the lists based on their overall position.
For instance:
mylist = [['h','e','l','l','o'], ['w','o','r','l','d']]
I want to change position 5 as if it was all one list resulting in:
[['h','e','l','l','o'], ['change','o','r','l','d']]
This is for very large lists and lots of mutations so speed is essential!

Here is the solution of your's question
# initializing list
input_list = [['h', 'e', 'l', 'l', 'o'], ['w', 'o', 'r', 'l', 'd']]
print("The initial list is : " + str(input_list))
length: int = 0
# define position(global index) where you want to update items in list
change_index = 5
## global starting index of sublist [0,5]
sub_list_start_index: list = list()
for sub_list in input_list:
sub_list_start_index.append(length)
length += len(sub_list)
# check if index we want to change is <= global list index and
if change_index <= length - 1 and change_index >= max(sub_list_start_index):
sub_list_index = int(change_index - max(sub_list_start_index))
input_list[input_list.index(sub_list)][sub_list_index] = 'change'
print("Updated list : " + str(input_list))
Output:
The initial list is : [['h', 'e', 'l', 'l', 'o'], ['w', 'o', 'r', 'l', 'd']]
Updated list : [['h', 'e', 'l', 'l', 'o'], ['change', 'o', 'r', 'l', 'd']]

Related

Once the end of a list is reached go back to the beginning, python

I have the list "alphabet" that has all the letters, and the program should with a certain word generate a sequence of letters using an number that gives the user, eg:
Word input = "sun"
Shift_number input = 3
alphabet = ['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']
The output should be "vxq" because the index moved three spaces to the right, my problem is when the moves of the index exceeds the number of variables in the list, eg:
Word input = "zero"
Shift_number = 1
The output should be "afsp" but instead I get this error: "list index out of range". I just need that the index goes to "z" to "a"
Take modulus to stay within the array bounds (index % 26, returning a range between 0-25 in the alphabet array of size 26):
>>> "".join([alphabet[(alphabet.index(i) + 3) % 26] for i in "sun"])
'vxq'
>>> "".join([alphabet[(alphabet.index(i) + 1) % 26] for i in "zero"])
'afsp'
(alphabet.index(i) + N) % 26 will increment the index by N cyclically in your array.
Use itertools.cycle and string.ascii_lowercase:
from itertools import cycle
import string
circular_alphabet = cycle(string.ascii_lowercase)
"".join(next(circular_alphabet ) for _ in range(50))
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx'

Conditional Statement produces unintended output

I am currently experimenting with lists in python and am trying to create a program that will simulate a name game (click here for reference).
The program asks for user's input and generates a list with each letter of the user's name. It then has to generate 3 new names, each beginning with "b", "f", "m".
So Robert would become:
[['b', 'o', 'b', 'e', 'r', 't'], ['f', 'o', 'b', 'e', 'r', 't'],
['m', 'o', 'b', 'e', 'r', 't']]
However, in cases where the name begins with the same letter, the first letter is simply removed, so Billy would become
[['i', 'l', 'l', 'y'], ['f', 'i', 'l', 'l', 'y'], ['m', 'i', 'l',
'l', 'y']]
However, when I run my code instead the output is:
[['b', 'i', 'l', 'l', 'y'], ['f', 'i', 'l', 'l', 'y'], ['m', 'i',
'l', 'l', 'y']]
Can anyone help? Is there an error in my conditional? Heres my code:
# Asks for user name
user_name = input("Enter name here: ")
name = list(user_name)
# Create an empty list that will contain a subsets of lists.
master_list = []
# List containing the first letter of each new name
beginning_of_word = ["b", "f", "m"]
# Creates 3 new names and appends them to master_list
for var in beginning_of_word:
new_list = list(name)
# if new_list[0] != 'B' or new_list[0] != 'F' or new_list[0] != 'M':
if 'B' not in new_list or 'F' not in new_list or 'M' not in new_list:
new_list.pop(0)
new_list.insert(0, var)
master_list.append(new_list)
else:
new_list.pop(0)
master_list.append(new_list)
print(master_list)
I have made a small correction in your condition statement. In your original program, the else block was getting skipped. In this approach, we first check for the values that are to be removed and then perform replacement in else block of the code. Secondly, the program is case sensitive. You have your characters in Uppercase in condition statement but in your lists, they are lowercase. In the approach below they are all lowercase. If you want it to be robust, you can add or or convert the input to lowercase before doing any operation.
user_name = input("Enter name here: ")
name = list(user_name)
# Create an empty list that will contain a subsets of lists.
master_list = []
# List containing the first letter of each new name
beginning_of_word = ["b", "f", "m"]
# Creates 3 new names and appends them to master_list
for var in beginning_of_word:
new_list = list(name)
if (("b" in new_list) or ("f" in new_list) or ("m" in new_list)):
new_list.pop(0)
#new_list.insert(0,)
master_list.append(new_list)
else:
new_list.pop(0)
new_list.insert(0,var)
master_list.append(new_list)
print(master_list)
The output is
Enter name here: john
[['b', 'o', 'h', 'n'], ['f', 'o', 'h', 'n'], ['m', 'o', 'h', 'n']]
Enter name here: billy
[['i', 'l', 'l', 'y'], ['i', 'l', 'l', 'y'], ['i', 'l', 'l', 'y']]

Joining & printing characters into a string from a 2d array

Might be a simple fix but I've tried everything. I'm trying to join and print the values from my 2d array in a single string without each character being separated if not separated by an actual space. For example what my code does now "H E L L O W O R L D" instead of "HELLO WORLD". Can someone please help.
for a in range(int(numOfColumns)):
for b in range(numOfRows):
#''.join(Matric[b][a])
#print(Matrix[b][a]),
#print(Matrix[b][a]),
You can use a list comprejesions:
result = " ".join(["".join([i for i in row]) for row in Matrix])
Or just
result = " ".join(["".join(row) for row in Matrix])
as #Tomothy32 noted.
Here an expression
"".join(row)
which creates a string from a row, for example:
row = ['h', 'e', 'l', 'l', 'o']
"".join([row])
Out:
hello
Almost the same for the outer loop which iterates the row, but it joins the strings with a whitespaces:
result = " ".join(...)
Or you can do it step-by-step, but it's not so clear:
substrings = []
for row in Matrix:
substr = ""
for char in row:
substr += char
substrings.append(substr)
result = " ".join(substrings)
I don't know how to do that easily without comprehensions. Probably you should use it.
Edit
How it works:
Matrix = [
['H', 'e', 'l', 'l', 'o'], # it's a first row
['w', 'o', 'r', 'l', 'd'] # it's a second row
]
Python iterastes trough the outer level first, i.e.
[print(row) for row in Matrix]
will print something like that:
['H', 'e', 'l', 'l', 'o'],
['w', 'o', 'r', 'l', 'd']
each row is a list (in this case). So, we can iterate through it, using inner loop (list comprehension):
[[print(i, end='') for i in row]) for row in Matrix]
Out:
"hello"
"world"
(end='' just cahnges newline to the empty string). Now you can change print to the "".join method and get what you want.
How iterate columns? Well, it's not so easy, especially when lengths of the strings are different. If the length is equal, you could use dollowing comprehension (answered here):
[[row(i) for row in matrix] for i in range(max(len(r) for r in Matrix))]
Out:
[['h', 'w'],
['e', 'o'],
['l', 'r'],
['l', 'l'],
['o', 'd']]
But probably it's easier to generate you data already transposed. There are some tutorials about a comprehensions, you can read it, for example, this one. Comprehensions is a very useful tool.
Assuming below martix:
Matric = [['h', 'e', 'l', 'l', 'o'], ['w', 'o', 'r', 'l', 'd']]
mat = ''
for x in Matric[0]:
mat = ''.join([mat,x])
mat += ' '
for y in Matric[1]:
mat = ''.join([mat, y])
print(mat)

List shuffling by range

I have a list full of strings. I want to take the first 10 values, shuffle them, then replace the first 10 values of the list, then with values 11-20, then 21-30, and so on.
For example:
input_list = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t']
and a function called:
shuffle10(input_list)
>>> ['d','b','c','f','j','i','h','a','e','g','m','n','s','r','k','p','l','q','o','t']
I thought it'd work if I defined an empty list and appended every 10 values randomized:
newlist=[]
for i in range(int(len(input_list) / 10)):
newlist.append(shuffle(input_list[(i*10):(i+1)*10]))
print(newlist)
but all this returns is:
[None]
[None, None]
Use random.sample instead of shuffle
>>> input_list = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t']
>>> sum((random.sample(input_list[n:n+10], 10) for n in range(0,len(input_list),10)), [])
['f', 'i', 'd', 'a', 'g', 'j', 'e', 'c', 'b', 'h', 'p', 'l', 'r', 'q', 'm', 't', 's', 'n', 'o', 'k']
You're creating a temp list in place and shuffling it but not capturing its results. You can pull out the relevant sublist, shuffle, then create a new list:
new_list=[]
for i in range(1, len(input_list), 10):
list_slice = input_list[i:i + 10]
shuffle(list_slice)
new_list.extend(list_slice)
print(new_list)

How to delete one of each item in a python list

I have a list that looks like this:
lst = ['p','p','p','p','p','m','m','m','n','n','n','n','d','d']
I want to remove one of each item. Currently my code looks like this:
for item in lst:
if (lst[-1] == lst[-2]) == True:
del(lst[-2])
That is if the last two items of the list are the same the second
from the last should be deleted, but my code does not work.
You can make a set of the unique characters, loop over a copy of your list, and then remove items from the set while adding to an output list:
lst = ['p','p','p','p','p','m','m','m','n','n','n','n','d','d']
chars_to_remove = set(lst)
counter = len(chars_to_remove)
output = []
for item in lst[:]:
if item in chars_to_remove:
chars_to_remove.remove(item)
continue
else:
output.append(item)
print(output)
Result:
['p', 'p', 'p', 'p', 'm', 'm', 'n', 'n', 'n', 'd']
Note: You still need to define what happens when there is only a single instance of a string in your list. (i.e. Does it get deleted as well?) In the above code, it will be deleted. But that can be changed like so, by adding another condition to the loop body:
Sample input : lst = ['p','p','p','p','p','m','m','m','q','n','n','n','n','d','d']
for item in lst[:]:
if lst[:].count(item) == 1:
output.append(item)
continue
elif item in chars_to_remove:
chars_to_remove.remove(item)
continue
else:
output.append(item)
Result:
['p', 'p', 'p', 'p', 'm', 'm', 'q', 'n', 'n', 'n', 'd']
You can also, use sum and groupby:
from itertools import groupby
lst = ['p', 'p', 'p', 'p', 'p', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'd', 'd']
final = sum((list(g)[:-1] for _, g in groupby(lst)), [])
print(final)
Output:
['p', 'p', 'p', 'p', 'm', 'm', 'n', 'n', 'n', 'd']
You could give this a shot
result = []
for _, u in groupby(lst):
new_u = list(u)
last_index = max(1, len(new_u) - 1)
result += new_u[:last_index]
It is not clear what your expected result it. Your code will not work because you are iterating a list while mutating it. Instead, iterate over a copy (lst[:]).
for item in lst[:]:
if (lst[-1] == lst[-2]):
del(lst[-2])
lst
# ['p', 'p', 'p', 'p', 'p', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'd']
However, you code still needs more to resolve:
I want to remove one of each item
Try this instead:
import itertools as it
lst = ['p','p','p','p','p','m','m','m','n','n','n','n','d','d']
list(it.chain.from_iterable((list(g)[:-1] for _, g in it.groupby(lst))))
# ['p', 'p', 'p', 'p', 'm', 'm', 'n', 'n', 'n', 'd']
Assuming you want to remove single occurrences in the list, can be done in one line:
[lst.remove(c) for c in set(lst)]
This does not return the answer, but modifies your list in place, so lst is now trimmed.
Or wrapped into a potentially more useful function:
def remove_first_occurence(lst):
l = lst.copy()
[l.remove(c) for c in set(l)]
return l

Categories