Recursive function in Python does not change list [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
I am using a recursive function on a list of lists with an accumulator, but instead of creating the right list of lists, it makes a list with duplicates of the last item inserted in the accumulator. I recreated the problem in a much simpler recursive function and list. This function takes a list of lists and makes 2 copies and reverses them n times.
def recursauto(x, n, instSet):
#Base Case
if(n==0):
instSet.append(x)
print(x) #Print to see what SHOULD be added
else:
temp = [x]*(2) # Make a list with 2 copies of the original list
for i in range(len(temp)):
temp[i][i] = temp[i][i][::-1] # Make the list backwards
for i in range(2):
recursauto(temp[i], n-1, instSet) #Input each element
MyList = [] #Empyt list for accumulator
print("Correct output:")
recursauto([["A", "l", "e", "x"], ["A", "b", "d", "a", "l", "a", "h"]], 2, MyList)
print("Wrong printed list:")
for i in MyList:
print(i) #Print what is in the accumulator
The output comes out wrong and the accumulator does not have the right things that were put into it.
Correct output:
[['A', 'l', 'e', 'x'], ['A', 'b', 'd', 'a', 'l', 'a', 'h']]
[['A', 'l', 'e', 'x'], ['A', 'b', 'd', 'a', 'l', 'a', 'h']]
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
Wrong printed list:
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
[['x', 'e', 'l', 'A'], ['h', 'a', 'l', 'a', 'd', 'b', 'A']]
I know that there is an easier way to do this, but the function I'm actually making requires recursion. Like I said, this is just a simplified recreation of the problem I am having.

temp = [x]*(2)
The above line does not create a list of two copies of the original list; in fact, it just stores a reference to the same original list twice. If you want a distinct copy of x, try using the list copy constructor like temp = [list(x), list(x)] or alternatively the shallow copy method [x.copy() x.copy()].
See the below example.
>>> ls = ['a']
>>> dup = [ls] * 2
>>> dup
[['a'], ['a']]
>>> ls.append('b')
>>> dup
[['a', 'b'], ['a', 'b']]

Related

Combine a list of list by element in python [duplicate]

This question already has answers here:
Transpose list of lists
(14 answers)
Closed last month.
I have a list of 4 list show below.
list1 = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['j', 'k', 'l']]
How do I create a list of list by element position so that the new list of list is as follows?
list2 = [['a', 'd', 'g', 'j'], ['b', 'e', 'h', 'k'], ['c', 'f', 'i', 'l']]
I tried using a for loop such as
res = []
for listing in list1:
for i in list:
res.append(i)
however it just created a single list.
Use zip with the * operator to zip all of the sublists together. The resulting tuples will have the list contents you want, so just use list() to convert them into lists.
>>> list1 = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['j', 'k', 'l']]
>>> [list(z) for z in zip(*list1)]
[['a', 'd', 'g', 'j'], ['b', 'e', 'h', 'k'], ['c', 'f', 'i', 'l']]

Subset a list in python on pre-defined string

I have some extremely large lists of character strings I need to parse. I need to break them into smaller lists based on a pre-defined character string, and I figured out a way to do it, but I worry that this will not be performant on my real data. Is there a better way to do this?
My goal is to turn this list:
['a', 'b', 'string_to_split_on', 'c', 'd', 'e', 'f', 'g', 'string_to_split_on', 'h', 'i', 'j', 'k', 'string_to_split_on']
Into this list:
[['a', 'b'], ['c', 'd', 'e', 'f', 'g'], ['h', 'i', 'j', 'k']]
What I tried:
# List that replicates my data. `string_to_split_on` is a fixed character string I want to break my list up on
my_list = ['a', 'b', 'string_to_split_on', 'c', 'd', 'e', 'f', 'g', 'string_to_split_on', 'h', 'i', 'j', 'k', 'string_to_split_on']
# Inspect List
print(my_list)
# Create empty lists to store dat ain
new_list = []
good_letters = []
# Iterate over each string in the list
for i in my_list:
# If the string is the seporator, append data to new_list, reset `good_letters` and move to the next string
if i == 'string_to_split_on':
new_list.append(good_letters)
good_letters = []
continue
# Append letter to the list of good letters
else:
good_letters.append(i)
# I just like printing things thay because its easy to read
for item in new_list:
print(item)
print('-'*100)
### Output
['a', 'b', 'string_to_split_on', 'c', 'd', 'e', 'f', 'g', 'string_to_split_on', 'h', 'i', 'j', 'k', 'string_to_split_on']
['a', 'b']
----------------------------------------------------------------------------------------------------
['c', 'd', 'e', 'f', 'g']
----------------------------------------------------------------------------------------------------
['h', 'i', 'j', 'k']
----------------------------------------------------------------------------------------------------
You can also use one line of code:
original_list = ['a', 'b', 'string_to_split_on', 'c', 'd', 'e', 'f', 'g', 'string_to_split_on', 'h', 'i', 'j', 'k', 'string_to_split_on']
split_string = 'string_to_split_on'
new_list = [sublist.split() for sublist in ' '.join(original_list).split(split_string) if sublist]
print(new_list)
This approach is more efficient when dealing with large data set:
import itertools
new_list = [list(j) for k, j in itertools.groupby(original_list, lambda x: x != split_string) if k]
print(new_list)
[['a', 'b'], ['c', 'd', 'e', 'f', 'g'], ['h', 'i', 'j', 'k']]

Reordering a list in a given order

I want to reorder my list in a given order,
For example I have a list of ['a', 'b', 'c', 'd', 'e', 'f', 'g']
this has an index of [0,1,2,3,4,5,6] and lets say the new ordered list would have an order of [3,5,6,1,2,4,0] which would result in ['d','f','g', 'b', 'c', 'e', 'a'].
How would you result in such code?
I thought of using for loop by doing the
for i in range(Len(list))
and after that I thought go using append or creating a new list? maybe but I'm not sure if I'm approaching this right.
All you need to do is iterate the list of indexes, and use it to access the list of elements, like this:
elems = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
idx = [3,5,6,1,2,4,0]
result = [elems[i] for i in idx]
print(result)
Output:
['d', 'f', 'g', 'b', 'c', 'e', 'a']
import numpy as np
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
def my_function(my_list, index):
return np.take(my_list, index)
print(my_function(my_list, [3,5,6,1,2,4,0]))
Output: ['d' 'f' 'g' 'b' 'c' 'e' 'a']

How to split a list and into a tuple

If i have a list
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
and I want to split into new list without 'k', and turn it into a tuple. So I get
(['a'],['b', 'c'], ['d', 'e', 'g'])
I am thinking about first splitting them into different list by using a for loop.
new_lst = []
for element in lst:
if element != 'k':
new_ist.append(element)
This does remove all the 'k' but they are all together. I do not know how to split them into different list. To turn a list into a tuple I would need to make a list inside a list
a = [['a'],['b', 'c'], ['d', 'e', 'g']]
tuple(a) == (['a'], ['b', 'c'], ['d', 'e', 'g'])
True
So the question would be how to split the list into a list with sublist.
You are close. You can append to another list called sublist and if you find a k append sublist to new_list:
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
new_lst = []
sublist = []
for element in lst:
if element != 'k':
sublist.append(element)
else:
new_lst.append(sublist)
sublist = []
if sublist: # add the last sublist
new_lst.append(sublist)
result = tuple(new_lst)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
If you're feeling adventurous, you can also use groupby. The idea is to group elements as "k" or "non-k" and use groupby on that property:
from itertools import groupby
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
result = tuple(list(gp) for is_k, gp in groupby(lst, "k".__eq__) if not is_k)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
Thanks #YakymPirozhenko for the simpler generator expression
tuple(list(i) for i in ''.join(lst).split('k'))
Output:
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Here's a different approach, using re.split from the re module, and map:
import re
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
tuple(map(list, re.split('k',''.join(lst))))
(['a'], ['b', 'c'], ['d', 'e', 'g'])
smallerlist = [l.split(',') for l in ','.join(lst).split('k')]
print(smallerlist)
Outputs
[['a', ''], ['', 'b', 'c', ''], ['', 'd', 'e', 'g']]
Then you could check if each sub lists contain ''
smallerlist = [' '.join(l).split() for l in smallerlist]
print(smallerlist)
Outputs
[['a'], ['b', 'c'], ['d', 'e', 'g']]
How about slicing, without appending and joining .
def isplit_list(lst, v):
while True:
try:
end = lst.index(v)
except ValueError:
break
yield lst[:end]
lst = lst[end+1:]
if len(lst):
yield lst
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g', 'k']
results = tuple(isplit_list(lst, 'k'))
Try this, works and doesn't need any imports!
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> t = []
>>> for s in ''.join(l).split('k'):
... t.append(list(s))
...
>>> t
[['a'], ['b', 'c'], ['d', 'e', 'g']]
>>> t = tuple(t)
>>> t
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Why don't you make a method which will take a list as an argument and return a tuple like so.
>>> def list_to_tuple(l):
... t = []
... for s in l:
... t.append(list(s))
... return tuple(t)
...
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> l = ''.join(l).split('k')
>>> l = list_to_tuple(l)
>>> l
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Another approach using itertools
import more_itertools
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
print(tuple(more_itertools.split_at(lst, lambda x: x == 'k')))
gives
(['a'], ['b', 'c'], ['d', 'e', 'g'])

Extend: merge strings on a list from other lists (or variables) at the same time [duplicate]

This question already has answers here:
Possible to append multiple lists at once? (Python)
(7 answers)
Closed 6 years ago.
I have 3 different lists and I need to merge them. It is easy when you need to extend a list with just an element or adding an inteire list. But with more lists or adding a variable in the middle, it seems impossible.
list1 = [ 'a', 'b', 'c']
list2 = [ 'd', 'e', 'f']
list3 = ['g', 'h', 'i']
Adding just one list:
list1.extend(list3)
Return:
['a', 'b', 'c', 'g', 'h', 'i']
Adding two lists:
list1.extend((list2,list3))
Return two lists inside another list:
['a', 'b', 'c', ['d', 'e', 'f'], ['g', 'h', 'i']]
Adding two list with operator '+':
list1.extend((list2 + list3))
Returns
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
but if you need to do something like:
list1.extend(('test' + list2 + fetch[0] + list3 + etc, etc, etc))
will not works.Can't concatenate.
A temporary solution adding a loop could be:
for l1 in list2:
list1.extend(l1)
for l2 in list3:
list1.extend(l2)
to finally have:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
Clearly a waste of lines and cycles
Is there a more efficient way to archive that without using external modules?
EDIT: the example of simple lists is just to understand what basically I need. The real problem is adding string or number or index on a single line of '.extend'.
SOLVED:
Wayne Werner drive me to the right direction to concatenate different type of elements.
list1 = [ 'a', 'b', 'c']
list2 = [ 'd', 'e', 'f']
list3 = ['g', 'h', 'i']
for other_list in (['test'], str(1), list2[2], list2[1]):
list1.extend(other_list)
Result:
['a', 'b', 'c', 'test', '1', 'f', 'e']
If you're looking for a clean way of extending a single list with N number of other lists, it's as simple as that:
my_list = ['a', 'b', 'c']
for other_list in (some_iterable, some_other_iterable, another_iterable):
my_list.extend(other_list)
I can't think of any more reasonable solution than that.
Just use extend for each of the lists you want to add on:
list1.extend(list2)
list1.extend(list3)
You can extend one of the lists with the addition of the other two:
list1 = [ 'a', 'b', 'c']
list2 = [ 'd', 'e', 'f']
list3 = ['g', 'h', 'i']
list3.extend(lis1 + list2)

Categories

Resources