I am somewhat inexperienced with programming, and I am a little confused about how the return function works. I am trying to write a program that maps a function onto the elements of a nested list. The variable levels represents the number of times nested levels there are in the list. I currently can get the program to work by printing my final mapped list, totlist:
def map_nested(listbasket, function, levels): #listbasket is the list that contains lists
totlist=[] #this list will store the list after the function has been mapped to it
for listelement in listbasket:
if levels<=2: #once we get to the level that just contains a list of lists
newlist=list(map(function,listelement))
totlist.append(newlist) #add to final mapped list
else:
map_nested(listelement, function, levels-1) #recursively call for next level
print(totlist)
map_nested([[[1,2],[3,4]],[[5,6],[7,8]]], math.sqrt, 3) # my test function
Instead, I want something that returns the totlist, but I can't figure out how to do this. everytime I try returning it, it just returns an empty list or part of the list. I feel like i've tried every configuration of returns I can think of.
This will work:
import math
def map_nested(listbasket, function, levels): #listbasket is the list that contains lists
totlist=[] #this list will store the list after the function has been mapped to it
for listelement in listbasket:
if levels<=2: #once we get to the level that just contains a list of lists
newlist=list(map(function,listelement))
totlist.append(newlist) #add to final mapped list
else:
totlist.append(map_nested(listelement, function, levels-1))
return totlist
map_nested([[[1,2],[3,4]],[[5,6],[7,8]]], math.sqrt, 3) # my test function
or a slightly neater solution:
import math
def map_nested(input, function):
if type(input) is list:
return [map_nested(e, function) for e in input]
else:
return function(input)
print map_nested([[[1,2],[3,4]],[[5,6],[7,8]]], math.sqrt)
This is recursively applying the map_nested method to every list in your hierarchy. When the recursion reaches an element in a list, it applies the function provided in the original call.
Note that this works on arbitrarily deeply nested lists, and also works on unbalanced nested lists (e.g., [1, 2, [3, 4]]).
I would make totlist an argument:
def map_nested(listbasket, function, levels, totlist=None):
if totlist is None:
totlist = []
for listelement in listbasket:
if levels <= 2:
newlist = list(map(function, listelement))
totlist.append(newlist) #add to final mapped list
else:
map_nested(listelement, function, levels-1, totlist)
return totlist
Now:
>>> map_nested([[[1,2],[3,4]],[[5,6],[7,8]]], math.sqrt, 3)
[[1.0, 1.4142135623730951],
[1.7320508075688772, 2.0],
[2.23606797749979, 2.449489742783178],
[2.6457513110645907, 2.8284271247461903]]
If you want to simplify (not manually passing levels) and flatten the nest as you go, something like:
def map_nested_2(lst, f, out=None):
if out is None:
out = []
for item in lst:
if isinstance(item, list):
map_nested_2(item, f, out)
else:
out.append(f(item))
return out
Would give:
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979,
2.449489742783178, 2.6457513110645907, 2.8284271247461903]
Related
I'm trying to return true if only all the previous elements are true up to the current position.
I have it set up with all function but I don't want to code it this way
def check(lightsOnOff, light):
for light in lights[:light]:
if not on:
return False
return True
count = count + 1
In general all is a useful construct to use, I can see why it looks wrong in this expression
all(list(lightsOnOff.values())[:light])
but the smelly part is actually the list(iterable)[:number] construction, which forces construction of the whole list then truncates it.
As an important aside, if lightsOnOff is a dict (not e.g. an OrderedDict) your code will be non-deterministic (see notes at bottom).
If you don't want to create a list and slice it, you can leverage itertools:
from itertools import islince
...
all(islice(lightsOnOff.values(), n))
As a frame challenge, if your dict has an order and you know the keys, you can simply rewrite it as:
all(lightsOnOff[k] for k in keys[:light])
and if your dict has keys that are ordered and e.g. integers, just use a list?
all(listOfLights[:light])
Provided you want to implement all yourself on an arbitrary list, you can do something like:
my_list = [1, 7, 2, 1, None, 2, 3]
up_to_ix = 5
def my_all(some_list, up_to_index):
for element in some_list[:up_to_index]:
if not element:
return False
return True
my_all(my_list, up_to_ix)
The function will loop through all elements in the list up to, but excluding the some_index and if it finds at least one Falsy value, will return False, otherwise True.
I have a list containing lists of objects. More specifically,
l = [ [X1,X2],[X3,X4]]
where X1,X2,X3,X4 are objects.
Now, I have a method in the class definition, that takes a list of objects, and modifies the attribute of the present object. Thus,
Class X:
def __init__(self,value=1):
self.value = value
def func (self,l):
total = 0
for x in l:
total += x.value
self.value = total
The problem I encounter is as follows. I have to apply the function func on elements of l[1] using elements of l[0]. However, when I do so, it turns out that the elements of l[0] are also getting changed. Thus, when I input
for obj in l[1]:
obj.func(l[0])
then I see that elements of l[0] have values that should ideally be assigned to l[1].
the list lis created as follows.
l0 = []
for i in range(2):
newx= X(i)
l.append(newx)
l=[]
l.append(l0)
l.append(l0)
What am I missing?
Correction: It seems python doesn't create new list objects every time I append an existing list.I basically need to copy the list using copy command. Hence, it is modifying the existing object.
l.append(l0)
l.append(l0)
Here you are appending the same list twice. Changes to objects in one list will be seen in the other because they are the same list.
To get the result you want, you must create two lists rather than reuse the first list.
I am looking for a simple way to compare the content of multiple lists and find the one with the fewest variables.
Then I want to set the new variable to be added to that list.
Example:
list1 = [1,5,7,12,4,8]
list2 = [3,2,9,11,14,6,10]
list3 = [13,15,16]
In this I would want it to find list3 to be the shortest and append the new value to it.
Due to pythons min, max, and sort's key keyword argument this is fairly simple to do in python
min([list1, list2, list3..], key = len).append(item)
key corresponds to the function applied to each element and whose result is used for comparison in both min and max. in this case the function len (which retrieves the length of sequence objects like list and tuple and any class that defines __len__ ) is used.
from min.
The key argument specifies a one-argument ordering function like that used for list.sort()
from list.sort()
key specifies a function of one argument that is used to extract a comparison key from each list element (for example, key=str.lower).
example
>>> x = [11231]
>>> y = [1,2,3,4,5]
>>> z = [1,2,3,4,1,1]
>>> min([x,y,z], key = len)
[11231]
You could write a small function that checks the len of each list, then append to that list.
def add_to_shortest(lists, item):
min(lists, key = lambda i: len(i)).append(item)
For example
>>> add_to_shortest([list1, list2, list3], 5)
>>> list3
[13, 15, 16, 5]
I am new to Python, therefore my question will look like pretty foolish.
I try to make some program that makes two-dimensional array. One function puts items to list and returns an array. Then, second function put results of the first function and puts it in outer list.
My program looks like this:
def get_matrix():
d = some_dict
matrix = list()
while len(matrix)<3:
row = get_row(d)
matrix.append(row)
return matrix
def get_row(dict):
array = list()
for t in range(3):
a = dict.popitem()
array.append(a)
return array
some_dict = dict()
for x in range(9):
some_dict[x] = "a"+str(x)
print(some_dict)
print(get_matrix())
It works well. But what if I want not to change list d in outer function but just do it so:
def get_matrix():
d = some_dict
matrix = list()
while len(matrix)<3:
row = get_row(d)
matrix.append(row)
for x in row:
d.pop(x)
return matrix
In other words, I want to keep the whole dict in outer function.
Actually I want know why the outer values change if we change only the dict given by arguments of inner function?
You are popping items of the dict in the inner function. Since you are passing a handle to a mutable object (dict) to your get_row() function, the popping will effect the dict in the outer get_matrix as well.
Note that a dict as a complex object behaves differently in that regard than an immutable parameters (int, float, str, etc.). Their values remain unchanged.
You could pass a copy of your dict
row = get_row(copy.deepcopy(d))
as explained here: Understanding dict.copy() - shallow or deep?.
Btw, you can access the values in your dict without popping them
def get_row(dict):
...
for t in range(3):
...
# a = dict.popitem()
a = dict[t]
which will also leave the dict unharmed.
Without any heavy libraries such as numpy, I want to uniformly handle a single list or multi-dimensional list in my code. For example, the function sum_up(list_or_matrix) should
return 6 for argument [1, 2, 3] and return 9 for [[1, 2, 3], [1, 2, 0]].
My question is:
1. Can I code in a way without explicitly detecting the dimension of my input such as by isinstance(arg[0], (tuple, list))?
2. If I have to do so, is there any elegant way of detecting the dimension of a list (of list of list ...), e.g. recursively?
As many users suggested you can always use dict instead of list for any-dimensinal collection. Dictionaries are accepting tuples as arguments as they are hashable. So you can easy fill-up your collection like
>>> m = {}
>>> m[1] = 1
>>> m[1,2] = 12
>>> m[1,2,"three",4.5] = 12345
>>> sum(m.values()) #better use m.itervalues() in python 2.*
12358
You can solve this problem using recursion, like this:
#!/usr/bin/env python
def sum(seq_or_elem):
if hasattr(seq_or_elem, '__iter__'):
# We were passed a sequence so iterate over it, summing the elements.
total = 0
for i in seq_or_elem:
total += sum(i)
return total
else:
# We were passed an atomic element, the sum is identical to the passed value.
return seq_or_elem
Test:
>>> print(sum([1, 2, [3, [4]], [], 5]))
15
Well I dont see a way if you are planning to use a single function to sum up your list like sum_up(list_or_matrix).
If you are having a list of lists I would only imagine you need to loop through the list to find out if its a 1-D or a 2-D list. Anyway whats wrong in looping?
def sum_up(matrix):
2DMatrix = False
for item in matrix:
if type(item) == list:
2DMatrix = True
if(2DMatrix):
//sum 2d matrix
else:
//sum 1d matrix
A simple way to sum up a matrix is as follow:
def sum_up(matrix):
if isinstance(matrix, (tuple, list)):
return sum(matrix)
else:
return sum((sum(x) for x in matrix))
The 'else' branch uses list comprehension, a powerful and quick tool.
You could sum recursively until you have a scalar value:
def flatten(x):
if isinstance(x, list):
return sum(map(flatten, x))
return x
Note: you can use collections.Iterable (or another base class) instead of list, depending on what you want to flatten.