A program to mutate Nested Lists - python

Could someone help me do two things:
Review the code and see if it could be written in a better way.
Finish this program. I got stuck in trying to put the list back the way it is. i.e. a nested list of lists.
Here we go:
t = ['a', 'b', ['c', 'd'], ['e'], 'f']
def capitalize_list(t):
L = []
N = []
for i in range(len(t)):
if type(t[i]) == str:
L.append(t[i].capitalize())
if type(t[i]) == list:
L.extend(t[i])
for s in L:
N.append(s.capitalize())
print N
capitalize_list(t)
This code prints:
['A', 'B', 'C', 'D', 'E', 'F']
I need it to print:
['A', 'B', ['C', 'D'], ['E'], 'F']

You can use recursion:
def capitalize_list(t):
N = []
for i in range(len(t)):
if type(t[i]) == str:
N.append(t[i].capitalize())
if type(t[i]) == list:
N.append(capitalize_list(t[i]))
return N
Output:
['A', 'B', ['C', 'D'], ['E'], 'F']

An alternative way of doing this recursively:
def capitalize(item):
if type(item) is str:
return item.capitalize()
if type(item) is list:
return map(capitalize, item)
You could even do
def capitalize(item):
try:
return item.capitalize()
except AttributeError:
return map(capitalize, item)
-- which would use the capitalize method for any object that has it (such as a normal or unicode string) and attempt to iterate through any object that does not.

Related

Looping through list and nested lists in python

Im trying to add a prefix to a list of strings in Python. The list of strings may contain multiple levels of nested lists.
Is there a way to loop through this list (and its nested lists), while keeping the structure?
nested for-loops became unreadable very quick, and did not seem to be the right approach..
list = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee']]]
for i in list:
if isinstance(i, list):
for a in i:
a = prefix + a
#add more layers of for loops
else:
i = prefix + i
desired outcome:
prefix = "#"
newlist = ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
Thanks in advance!
You could write a simple recursive function
def apply_prefix(l, prefix):
# Base Case
if isinstance(l, str):
return prefix + l
# Recursive Case
else:
return [apply_prefix(i, prefix) for i in l]
l = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee',]]]
print(apply_prefix(l, "#"))
# ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
This will use recursion:
a = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee',]]]
def insert_symbol(structure, symbol='#'):
if isinstance(structure, list):
return [insert_symbol(sub_structure) for sub_structure in structure]
else:
return symbol + structure
print(insert_symbol(a))
>>> ['#a', '#b', ['#C', '#C'], '#d', ['#E', ['#Ee', '#Ee']]]
You can use a recursive code like this!, Try it, and if you have questions you can ask me
def add_prefix(input_list):
changed_list = []
for elem in input_list:
if isinstance(elem, list):
elem = add_prefix(elem)
changed_list.append(elem)
else:
elem = "#" + elem
changed_list.append(elem)
return changed_list
Maybe you can use a function to do it recursively.
list_example = ['a', 'b', ['C', 'C'], 'd', ['E', ['Ee', 'Ee']]]
def add_prefix(p_list, prefix):
for idx in range(len(p_list)):
if isinstance(p_list[idx], list):
p_list[idx] = add_prefix(p_list[idx], prefix)
else:
p_list[idx] = prefix + p_list[idx]
return p_list
add_prefix(list_example, '#')
edit: I see now someone has posted the almost same thing.
btw. it is considered bad practice to name a list list, since it is also a typename in python. Might result in unwanted behaviour

replace duplicate values in a list with 'x'?

I am trying to understand the process of creating a function that can replace duplicate strings in a list of strings. for example, I want to convert this list
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
to this
mylist = ['a', 'b', 'x', 'x', 'c', 'x']
initially, I know I need create my function and iterate through the list
def replace(foo):
newlist= []
for i in foo:
if foo[i] == foo[i+1]:
foo[i].replace('x')
return foo
However, I know there are two problems with this. the first is that I get an error stating
list indices must be integers or slices, not str
so I believe I should instead be operating on the range of this list, but I'm not sure how to implement it. The other being that this would only help me if the duplicate letter comes directly after my iteration (i).
Unfortunately, that's as far as my understanding of the problem reaches. If anyone can provide some clarification on this procedure for me, I would be very grateful.
Go through the list, and keep track of what you've seen in a set. Replace things you've seen before in the list with 'x':
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
seen = set()
for i, e in enumerate(mylist):
if e in seen:
mylist[i] = 'x'
else:
seen.add(e)
print(mylist)
# ['a', 'b', 'x', 'x', 'c', 'x']
Simple Solution.
my_list = ['a', 'b', 'b', 'a', 'c', 'a']
new_list = []
for i in range(len(my_list)):
if my_list[i] in new_list:
new_list.append('x')
else:
new_list.append(my_list[i])
print(my_list)
print(new_list)
# output
#['a', 'b', 'b', 'a', 'c', 'a']
#['a', 'b', 'x', 'x', 'c', 'x']
The other solutions use indexing, which isn't necessarily required.
Really simply, you could check if the value is in the new list, else you can append x. If you wanted to use a function:
old = ['a', 'b', 'b', 'a', 'c']
def replace_dupes_with_x(l):
tmp = list()
for char in l:
if char in tmp:
tmp.append('x')
else:
tmp.append(char)
return tmp
new = replace_dupes_with_x(old)
You can use the following solution:
from collections import defaultdict
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
ret, appear = [], defaultdict(int)
for c in mylist:
appear[c] += 1
ret.append(c if appear[c] == 1 else 'x')
Which will give you:
['a', 'b', 'x', 'x', 'c', 'x']

How can I reverse a section of a list using a loop in Python?

I'm in need of a little help reversing a section of a list in Python using a loop.
I have a list: mylist = ['a', 'b', 'c', 'd', 'e', 'f']
Also have an index number, this number will tell where to start the reversing. For example, if the reverse-index number is 3, it needs to be something like this: ['d', 'c', 'b', 'a', 'e', 'f']
What I currently have:
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = []
for item in range( len(list1) ):
n_list.append( (list1[(reverse_index - 1) - item]) )
item += 1
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print( list_section_reverse(mylist, 3) )
Which returns ['c', 'b', 'a', 'f', 'e', 'd']
How can I alter my code, so that it prints out ['d', 'c', 'b', 'a', 'e', 'f']?
You can simply use:
def list_section_reverse(list1, reverse_index):
return list(reversed(list1[:reverse_index+1])) + list1[reverse_index+1:]
Edit: The problem with your existing solution is that you keep reversing after reverse_index. If you have to use a loop, try this:
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = list1[:]
for i in range(reverse_index + 1):
n_list[i] = list1[-i-reverse_index]
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print(list_section_reverse(mylist, 3))
The pythonic solution:
list1[reverse_index::-1] + list1[reverse_index+1:]
Now, that's not using loops like you asked. Well, not explicitly... Instead we can break down the above into its constituent for loops.
def list_section_reverse(list1, reverse_index):
if reverse_index < 0 or reversed_index >= len(list1):
raise ValueError("reverse index out of range")
reversed_part = []
for i in range(reverse_index, -1, -1): # like for i in [n, n-1, ..., 1, 0]
reversed_part.append(list1[i]
normal_part = []
for i in range(reverse_index + 1, len(list1)):
normal_part.append(list1[i])
return reversed_part + normal_part
Is it allowed to make a copy of the list?
def list_section_reverse(list1, reverse_index):
print("In function reverse()")
n_list = [ element for element in list1 ]
for item in range( reverse_index + 1 ):
n_list[ item ] = list1[ reverse_index - item ]
item += 1
return n_list
mylist = ['a', 'b', 'c', 'd', 'e', 'f']
print(list_section_reverse(mylist, 3))
Outs:
In function reverse()
['d', 'c', 'b', 'a', 'e', 'f']
You can modify the list inplace using a slice.
mylist[:4] = mylist[:4][::-1]
You can try this. This makes use of no slicing, and can use either a while loop or for loop.
def reversed_list(my_list, index):
result = []
list_copy = my_list.copy()
i = 0
while i < index+1:
result.append(my_list[i])
list_copy.remove(my_list[i])
i+=1
result.reverse()
return result + list_copy
Or with a for loop
def reversed_list(my_list, index):
result = []
list_copy = my_list.copy()
for i in range(len(my_list)):
if i < index + 1:
result.append(my_list[i])
list_copy.remove(my_list[i])
result.reverse()
return result + list_copy

Python: Search list and give boolean

If I have a list like so:
List = ['a', 'b', 'c', 'd', 'e',]
what is the simplest way to get a Boolean answer if, I for instance asked it if 'g' was inside this list?
print 'g' in ['a', 'b', 'c', 'd']
l = ['a','b','c','d']
if 'g' in l:
print True
List = ['a', 'b', 'c', 'd', 'e']
def inlist (lst, character):
if character in lst and type(lst) is list:
return True
else:
return False
print inlist(List, 'g')
As you expect, this prints: False
NOTE: try to name your lists other than List, as that can cause some confusion when reading.

How to create nested list from flatten list?

I wrote a function to create a nested list.
For example:
input= ['a','b','c','','d','e','f','g','','d','s','d','a','']
I want to create a sublist before ''
As a return I want a nested list like:
[['a','b','c'],['d','e','f','g'],['d','s','d','a']]
Try the following implementation
>>> def foo(inlist, delim = ''):
start = 0
try:
while True:
stop = inlist.index(delim, start)
yield inlist[start:stop]
start = stop + 1
except ValueError:
# if '' may not be the end delimiter
if start < len(inlist):
yield inlist[start:]
return
>>> list(foo(inlist))
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
Another possible implementation could be by itertools.groupby. But then you have to filter the result to remove the ['']. But though it might look to be one-liner yet the above implementation is more pythonic as its intuitive and readable
>>> from itertools import ifilter, groupby
>>> list(ifilter(lambda e: '' not in e,
(list(v) for k,v in groupby(inlist, key = lambda e:e == ''))))
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
I'd use itertools.groupby:
l = ['a','b','c','','d','e','f','g','','d','s','d','a','']
from itertools import groupby
[list(g) for k, g in groupby(l, bool) if k]
gives
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
def nester(nput):
out = [[]]
for n in nput:
if n == '':
out.append([])
else:
out[-1].append(n)
if out[-1] == []:
out = out[:-1]
return out
edited to add check for empty list at end

Categories