How to append elements in a list within a list? - python

I'd like to append elements to a sub-list within a main-list. The number of elements to be appended corresponds to the sub-list position in the main-list.
My code:
# define the maximum level of the game
max_level = 3
# create list with length = level
lsx = []
# append empty lists in lsy for every element in lsx
empty = []
lsy = []
def create_list(max_level):
for i in range(max_level):
integer = random.randint(1,5)
lsx.append(integer)
for j in lsx:
lsy.append(empty)
return(lsy)
create_list(max_level)
Output:
[[], [], []]
Desired output:
[[1], [1, 2], [1, 2, 3]]

You don't need (and shouldn't) use globals. When appending empty to lsy multiple times you are appending the same object - changing one will change other as well.
You can create the nested lists inside the loop:
import random
def create_list(max_level):
# top level list
res = []
for i in range(max_level):
# nested list
next_l = []
for j in range(i+1):
next_l.append(random.randint(1, 5))
res.append(next_l)
return res
print(create_list(3))
Output:
[[5], [4, 3], [2, 3, 2]]

Well, this could work
def create_list(max_level):
res = []
for i in range(max_level):
i += 1
res.append(list(range(i+1))[1:])
return res
Output
>>> create_list(5)
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]

Related

extracting index from a nested list

I would like to be able to get the index of each number in a nested list so for example i have the following list:
T = ['apple', [10, 5, ['orange']], 3]
and i would like to extract the values as such:
List of numbers: [10,5,3]
address of numbers: [[1, 0], [1, 1], [2]]
so for example, the number '3' is the third value in the list (index 2), where as the number '5' is the second value in the second list so it will be [1,1].
I've written the following recursive function with a for loop inside:
indices = []
List_numbers = []
Address_numbers = []
def Numbers(T):
for index, elem in enumerate(T):
if isinstance(elem, int):
List_numbers.append(elem)
Address_numbers.append(indices + [index])
if isinstance(elem, list):
indices.append(index)
Fruits(elem)
print('List of numbers: ' + str(List_numbers))
print('Address of numbers: ' + str(Address_numbers))
The problem with this code, is when it reaches the last value and needs to exit the list it keeps the same index so the address is outputs is this:
List of numbers: [10, 5, 3]
Address of numbers: [[1, 0], [1, 1], [1, 2, 2]]
I've tried everything to fix it but im honestly not sure how it would be possible to fix this, can anyone help?
Use a recursive function to extract index from nested list.
Using recursion you can extract index from nested list to any depth:
T = ['apple', [10, 5, ['orange']], 3]
total_numbers = []
indexes = []
def find_index_of_numbers(lisst, level):
for index, value in enumerate(lisst):
if isinstance(value, int):
total_numbers.append(value)
indexes.append([level, index])
elif isinstance(value, list):
find_index_of_numbers(value, level + 1)
find_index_of_numbers(T, 0)
print("My list--->", T)
print("Numbers--->", total_numbers)
print("Indexes--->", indexes)
Output
My list---> ['apple', [10, 5, ['orange']], 3]
Numbers---> [10, 5, 3]
Indexes---> [[1, 0], [1, 1], [0, 2]]

Subsets With Duplicates, issues with only returning empty list

I am working on a question as following:
Given a set of numbers that might contain duplicates, find all of its distinct subsets.
You can use the following as an example :
Example 1:
Input: [1, 3, 3]
Output: [], [1], [3], [1,3], [3,3], [1,3,3]
Example 2:
Input: [1, 5, 3, 3]
Output: [], [1], [5], [3], [1,5], [1,3], [5,3], [1,5,3], [3,3],
[1,3,3], [3,3,5], [1,5,3,3]
My approach is
class Solution:
def distinct_subset(self, nums):
n = len(nums)
previousEnd = 0
output = []
for i in range(n):
# judge if the current element is equal to the previous element
# if so, only update the elements generated in the previous iteration
if i > 0 and nums[i] == nums[i-1]:
previousStart = previousEnd + 1
else:
previousStart = 0
perviousEnd = len(output)
# create a temp array to store the output from the previous iteration
temp = list(output[previousStart:previousEnd])
# add current element to all the array generated by the previous iteration
output += [j + [nums[i]] for j in temp]
return output
def main():
print("Here is the list of subsets: " + str(Solution().distinct_subset([1, 3, 3])))
print("Here is the list of subsets: " + str(Solution().distinct_subset([1, 5, 3, 3])))
main()
However, my approach will only return []:
Here is the list of subsets: []
Here is the list of subsets: []
Process finished with exit code 0
I am not sure why did I go wrong. The algorithm supposes to update the output in each iteration. But now it failed.
Please feel free to share your ideas. Thanks for your help in advanced.
Yes, I ran your code and it appears no matter what you do the function will always return an output of an empty list, because nothing is actually changing in the list, it is always blank.
Forgive me, but I had to look up what 'all distinct subsets' meant, and I stumbled across this code, but it seems to do exactly what you are asking.
# Python3 program to find all subsets of
# given set. Any repeated subset is
# considered only once in the output
def printPowerSet(arr, n):
# Function to find all subsets of given set.
# Any repeated subset is considered only
# once in the output
_list = []
# Run counter i from 000..0 to 111..1
for i in range(2**n):
subset = ""
# consider each element in the set
for j in range(n):
# Check if jth bit in the i is set.
# If the bit is set, we consider
# jth element from set
if (i & (1 << j)) != 0:
subset += str(arr[j]) + "|"
# if subset is encountered for the first time
# If we use set<string>, we can directly insert
if subset not in _list and len(subset) > 0:
_list.append(subset)
# consider every subset
for subset in _list:
# split the subset and print its elements
arr = subset.split('|')
for string in arr:
print(string, end = " ")
print()
# Driver Code
if __name__ == '__main__':
arr = [10, 12, 12, 17]
n = len(arr)
printPowerSet(arr, n)
However, as you can see the above code does not use classes just a single function. If that works great, if you are required to use a class, let me know you will need to change the above code obviously.
I assume the below is what you are looking for:
[1, 3, 3] to [1,3]
[1, 5, 3, 3] to [1,5,3]
The set(list) function will do that for you real easy, however it doesn't handle compound data structure well.
Below code will work for compound data from, one level deep:
[[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]
to:
[[1, 1], [0, 1], [0, 0], [1, 0]]
code:
def get_unique(list):
temp = []
for i in list:
if i not in temp:
temp.append(i)
yield i
print(*get_unique(list))
I've trimmed the above code to give you your desired outputs, still not in a class though, is this okay?...
def distinct_subset(user_input):
n = len(user_input)
output = []
for i in range(2 ** n):
subset = ""
for j in range(n):
if (i & (1 << j)) != 0:
subset += str(user_input[j]) + ", "
if subset[:-2] not in output and len(subset) > 0:
output.append(subset[:-2])
return output
def main():
print("Here is the list of subsets: " + str(distinct_subset([1, 3, 3])))
print("Here is the list of subsets: " + str(distinct_subset([1, 5, 3, 3])))
main()
You're looking for distinct combinations of the powerset of your list.
Using itertools to generate the combinations and a set to eliminate duplicates, you could write the function like this:
from itertools import combinations
def uniqueSubsets(A):
A = sorted(A)
return [*map(list,{subset for size in range(len(A)+1)
for subset in combinations(A,size)})]
print(uniqueSubsets([1,3,3]))
# [[1, 3], [3, 3], [1], [3], [], [1, 3, 3]]
print(uniqueSubsets([1,5,3,3]))
# [1, 3] [3, 3] [1] [3] [3, 3, 5] [1, 3, 5] [1, 5] [5] [] [1, 3, 3, 5] [1, 3, 3] [3, 5]
If you have a lot of duplicates, it may be more efficient to filter them out as you go. Here is a recursive generator function that short-circuits the expansion when a combination has already been seen. It generates combinations by removing one element at a time (starting from the full size) and recursing to get shorter combinations.
def uniqueSubsets(A,seen=None):
if seen is None: seen,A = set(),sorted(A)
for i in range(len(A)): # for each position in the list
subset = (*A[:i],*A[i+1:]) # combination without that position
if subset in seen: continue # that has not been seen before
seen.add(subset)
yield from uniqueSubsets(subset,seen) # get shorter combinations
yield list(A)
print(*uniqueSubsets([1,3,3]))
# [] [3] [3, 3] [1] [1, 3] [1, 3, 3]
print(*uniqueSubsets([1,5,3,3]))
# [] [3] [3, 3] [5] [5, 3] [5, 3, 3] [1] [1, 3] [1, 3, 3] [1, 5] [1, 5, 3] [1, 5, 3, 3]
In both cases we are sorting the list in order to ensure that the combinations will always present the values in the same order for the set() to recognize them. (otherwise lists such as [3,3,1,3] could still produce duplicates)

Separating sublist into multiple list and assigning dynamic list_name

I am trying to split a nested list into multiple lists and assign their name dynamically. Untill now, I tried the code below, but it only works when we have equal length sublists and we give them names manually.
sub_list = [[1,2,3],[4,5,5], [2,63,6]]
l1, l2, l3 = map(list, zip(*sub_list))
print(l1)
print(l2)
print(l3)
# Output
[1, 4, 2]
[2, 5, 63]
[3, 5, 6]
The approach above will fail when we have unequal length sublists such as (sub_list = [[1,2,3],[4,5], [2]]) and it does not give lists dynamic names.
I know it can be done by for loop, but I am not able to make list_name using a loop.
Any help will help me to reach more closure to my work
you could use zip_longest from itertools as follows:
sub_list = [[1,2,3],[4,5], [2]]
from itertools import zip_longest
l1, l2, l3 = map(list, zip_longest(*sub_list))
print(l1)
print(l2)
print(l3)
Output:
# [1, 4, 2]
# [2, 5, None]
# [3, None, None]
Answering the first question: If you don't want to give a manual name assing the map() to just one variable:
sub_list = [[1,2,3],[4,5,5], [2,63,6]]
rotated = map(list, zip(*sub_list))
for r in rotated:
print(r)
# Output
# [1, 4, 2]
# [2, 5, 63]
# [3, 5, 6]
Not completely sure what you want to accomplish, but I suggest you take a look at:
How to use itertools.zip_longest(): Python: zip-like function that pads to longest length? (You can filter out the Nones afterwards)
How to create dynamically named vars (although this is generally not the best thing to do): How do I create a variable number of variables?
The following code performs in both of your special cases:
There are no errors if some input lists are shorter than others
Names are procedurally/dynamically generated
def rotate_list_matrix(rows):
nrows = len(rows)
col_counts = map(lambda lyst: len(lyst), rows)
ncols = max(col_counts)
for ci in range(0, ncols): # column index
lyst = list()
list_name = "l" + str(ci + 1)
globals()[list_name] = lyst
for ri in range(0, nrows):
try:
lyst.append(rows[ri][ci])
except:
break
return
list_mata = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
list_matb = [[1, 2, 3],
[4, 5 ],
[7 ]]
rotate_list_matrix(list_matb)
print(l1)
print(l2)
print(l3)

Python : Deep Reverse List

I have a nested list, and I need to reverse every element in the list.
Below is the example :
L = [[0, 1, 2], [1, 2, 3]]
Expected Output :
L = [[3, 2, 1], [2, 1, 0]]
I tried with the below piece of code, it works individually but when I am putting this code within function, then the list is not getting updated.
L = [list(reversed(row)) for row in L]
L.reverse()
This code works, and the List "L" is getting updated.
But when I put this code in function
def deep_rev(L):
L = [list(reversed(row)) for row in L]
L.reverse()
L = [[0, 1, 2], [1, 2, 3]]
deep_rev(L)
print(L)
This is returning the same list = [[0,1,2],[1,2,3]]
Can anyone please help me in this regard, why in function this is not working?
With L = ... you are assigning a new value to the parameter L within the function, without modifying the original list. Instead, you can use L[:] = ... to replace all the elements in the original list with the values from the new list.
def deep_rev(L):
L[:] = [list(reversed(row)) for row in reversed(L)]
L = [[0, 1, 2], [1, 2, 3]]
deep_rev(L)
print(L) # [[3, 2, 1], [2, 1, 0]]
Your current code creates a new list, rather than modifying the exiting list in place. You can make it work, just get rid of the list comprehension and do in-place reversals for the inner lists too:
def deep_rev(L):
for inner in L:
inner.reverse()
L.reverse()
If you want to support more than two levels of nesting, you could recursively call deep_rev on the inner lists, rather than just reversing them as I did above. You'd need to check if the values were lists or not, so you'd have a base case.
This is the solution I find out using recursion:
l=[[0, 1, 2], [1, 2, 3]]
def treereverse(l):
l.reverse()
for x in l:
if isinstance(x,list):
treereverse(x)
return l
print(treereverse(l))
This Code works for your problem,
L = [[0, 1, 2], [1, 2, 3]]
b=list(reversed(L))
q=[]
for i in b:
q.append(list(reversed(i)))
print q
Output:-
[[3, 2, 1], [2, 1, 0]]
def deep_rev(l):
l = [list(reversed(row)) for row in l]
l.reverse()
return l
l = [[0, 1, 2], [1, 2, 3]]
l = deep_rev(l)
print(l)
output
[[3, 2, 1], [2, 1, 0]]
deep_rev(L) modifies one local list, its scope is inside this function. Either make one deep copy of the list or return the reversed list.

Separating same numbers from the list and making the list of such lists [duplicate]

From this list:
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
I'm trying to create:
L = [[1],[2,2],[3,3,3],[4,4,4,4],[5,5,5,5,5]]
Any value which is found to be the same is grouped into it's own sublist.
Here is my attempt so far, I'm thinking I should use a while loop?
global n
n = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5] #Sorted list
l = [] #Empty list to append values to
def compare(val):
""" This function receives index values
from the n list (n[0] etc) """
global valin
valin = val
global count
count = 0
for i in xrange(len(n)):
if valin == n[count]: # If the input value i.e. n[x] == n[iteration]
temp = valin, n[count]
l.append(temp) #append the values to a new list
count +=1
else:
count +=1
for x in xrange (len(n)):
compare(n[x]) #pass the n[x] to compare function
Use itertools.groupby:
from itertools import groupby
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
print([list(j) for i, j in groupby(N)])
Output:
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
Side note: Prevent from using global variable when you don't need to.
Someone mentions for N=[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 1] it will get [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5], [1]]
In other words, when numbers of the list isn't in order or it is a mess list, it's not available.
So I have better answer to solve this problem.
from collections import Counter
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
C = Counter(N)
print [ [k,]*v for k,v in C.items()]
You can use itertools.groupby along with a list comprehension
>>> l = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
>>> [list(v) for k,v in itertools.groupby(l)]
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
This can be assigned to the variable L as in
L = [list(v) for k,v in itertools.groupby(l)]
You're overcomplicating this.
What you want to do is: for each value, if it's the same as the last value, just append it to the list of last values; otherwise, create a new list. You can translate that English directly to Python:
new_list = []
for value in old_list:
if new_list and new_list[-1][0] == value:
new_list[-1].append(value)
else:
new_list.append([value])
There are even simpler ways to do this if you're willing to get a bit more abstract, e.g., by using the grouping functions in itertools. But this should be easy to understand.
If you really need to do this with a while loop, you can translate any for loop into a while loop like this:
for value in iterable:
do_stuff(value)
iterator = iter(iterable)
while True:
try:
value = next(iterator)
except StopIteration:
break
do_stuff(value)
Or, if you know the iterable is a sequence, you can use a slightly simpler while loop:
index = 0
while index < len(sequence):
value = sequence[index]
do_stuff(value)
index += 1
But both of these make your code less readable, less Pythonic, more complicated, less efficient, easier to get wrong, etc.
You can do that using numpy too:
import numpy as np
N = np.array([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
counter = np.arange(1, np.alen(N))
L = np.split(N, counter[N[1:]!=N[:-1]])
The advantage of this method is when you have another list which is related to N and you want to split it in the same way.
Another slightly different solution that doesn't rely on itertools:
#!/usr/bin/env python
def group(items):
"""
groups a sorted list of integers into sublists based on the integer key
"""
if len(items) == 0:
return []
grouped_items = []
prev_item, rest_items = items[0], items[1:]
subgroup = [prev_item]
for item in rest_items:
if item != prev_item:
grouped_items.append(subgroup)
subgroup = []
subgroup.append(item)
prev_item = item
grouped_items.append(subgroup)
return grouped_items
print group([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
# [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]

Categories

Resources