How to apply function to list inside list? - python

I am writing code to sum the second index in a list within a list:
employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
i.e. I want to do 5+3+3= 11
for i in range(len(employees)):
total_importance = sum(input[i][1])
or
total_important = sum(map(list.append, input[i][1]))
print(total_importance)
Now both of the options above for total_importance produce an error- int object is not itterable or other errors. Is there any way I can amend the code above for it to work?
I have another method where I simply append input[i][1] into a new list and then sum from there, and this easily works. But for my knowledge I want to ask if there is any way to amend either of the code above? Thanks

You can use list comprehension to extract the second element and sum on that new list:
sum([l[1] for l in employees])
The above code returns 11 on your employees object.
This also works without creating a new list, by passing a generator to the sum function:
sum(l[1] for l in employees)

You can take advantage of pythons powerful unpack features:
sum(second for first,second,*rest in employees)
This will unpack into three variables, first, second and the rest (in case of uneven lengths).
If you only care to use the second you can use:
sum(second for _,second,*_ in employees)

The line where you wrote total_importance = sum(input[i][1]), inside the sum() you are basically extracting one integer from that list and using sum() on it. This is equivalent to doing sum(2) which would of course cause an error.
Instead, you can do
total_importance = 0
for i in range(len(employees)):
num = employees[i][1]
total_importance += num

You might consider to reduce the list to the desired sum
reduce((lambda x, y: x+y[1]), employees, 0)
EDIT: Please note that input is a built in function in python. In the above mentioned reduce method x represents the "running sum" of summed up elements and y represents an item from the employees list. So x is an int value and y is a list. 0 is the initial value for the calculation:
>>> import functools
>>> employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
>>> functools.reduce((lambda x, y: x+y[1]), employees, 0)
11

So, this is because you are using sum function which works on list. But you are selecting individual element. So you need to do:
total_importance += employees[i][1]
You can make this code more general like even if the second element is list, it will work.
# employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
employees = [[1, [5,6], [2, 3]], [2, 3, []], [3, 3, []]]
total_importance=0
for i in range(len(employees)):
if isinstance(employees[i][1], list):
total_importance += sum(employees[i][1])
else:
total_importance += employees[i][1]
print(total_importance)

Related

How to parse these operations through lists?

Program description:
Program accepts a list l containing other lists. Output l where lists with length greater than 3 will be changed accordingly: the element with index 3 is going to be a sum of removed elements (from third to the end).
My solution:
l = [[1,2], [3,4,4,3,1], [4,1,4,5]]
s = 0
for i in range(len(l)-1):
if len(l[i]) > 3:
for j in range(3,len(l[i])-1):
s += l[i][j]
l[i].remove(l[i][j])
l[i].insert(len(l[i]),s)
l
Test:
Input: [[1,2], [3,4,4,3,1], [4,1,4,5]]
Expected Output: [[1, 2], [3, 4, 8], [4, 1, 9]]
Program run:
Input: [[1,2], [3,4,4,3,1], [4,1,4,5]]
Output: [[1, 2], [4, 4, 3, 1, 3], [4, 1, 4, 5]]
Question: I don't understand what can be the source of the problem in this case, why should it add some additional numbers to the end, instead of summ. I will appreciate any help.
remove is the wrong function. You should use del instead. Read the documentation to understand why.
And another bug you have is that you do not reset s. It should be set to 0 in the outer for loop.
But you're making it too complicated. I think it's better to show how you can do it really easy.
for e in l: # No need for range. Just iterate over each element
if len(e) > 3:
e[2]=sum(e[2:]) # Sum all the elements
del(e[3:]) # And remove
Or if you want it as a list comprehension that creates a new list and does not alter the old:
[e[0:2] + [sum(e[2:])] if len(e)>3 else e for e in l]
First of all, remove() is the wrong method, as it deletes by value, not index:
Python list method remove() searches for the given element in the list
and removes the first matching element.
You'd want to use del or pop().
Second of all, you're not slicing all of the elements from the end of the list, but only one value.
remove is reason why your code is not working. (as mentioned by Mat-KH in the other answer)
You can use list comprehension and lambda function to make it a two liner.
func = lambda x: x if len(x) < 3 else x[:2] + [sum(x[2:])]
l = [func(x) for x in l]

how to split a list into a nested list in Python 3?

I want to split a list into a nest list. The list I have is this:
[1,2,1,3,2]
Now, I want the output to be like this:
[[1,2],[2,1],[1,3],[3,2]]
Is there any possible of doing the output as mentioned above?
You can use zip
lst = [1,2,1,3,2]
res = [list(pair) for pair in zip(lst, lst[1:])]
print(res) # -> [[1, 2], [2, 1], [1, 3], [3, 2]]
Note: the first instance of lst in zip does not have to be sliced since it is the smallest of the two that dictates the number of tuples that will be generated.
As #Jean-FrancoisFabre said in the comments, if the original list is big, you might want to go with a generator instead of a hard slice.
res = [list(pair) for pair in zip(lst, itertools.islice(lst, 1, None))]
The benefit of this approach (or the drawback of the previous one) is that the second list used in zip (lst[1:]) is not created in memory, but you will need to import itertools for it to work.
You're looking for bi-grams. Here is a generic function to generate n-grams from a sequence.
def ngrams(seq, n):
return [seq[i:i + n] for i in range(len(seq) - n + 1)]
a = [1,2,1,3,2]
print ngrams(a, 2)
# [[1, 2], [2, 1], [1, 3], [3, 2]]

Slicing a list with variable chunk size in Python [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 5 years ago.
I worked in Python 3.6, and I am a beginner. So can anyone give me a true way of how can slice a list into variable size sub-list. I tried this solution from this site, but it gave me fixed size of sliced list. To clarify:
if I have this list:
inputList= [0,1,2,3,4,5,6,7]
I want the output to be like e.g.:
outputList=[[0,1,2], [3,4], [5], [6,7]]
each time it depends on (for example) user input or some variable size.
Just use itertools.islice(). This has the added advantage that if you request a slice that you would normally take you out of bounds, you won't get an error. You'll just get as many items are left as possible.
>>> import itertools as it
>>> input_list = range(8)
>>> slices = (3, 2, 1, 2)
>>> iterable = iter(input_list)
>>> output_list = [list(it.islice(iterable, sl)) for sl in slices]
>>> output_list
[[0, 1, 2], [3, 4], [5], [6, 7]]
For example, if you had slices = (3, 2, 1, 3, 2), your result would be [[0, 1, 2], [3, 4], [5], [6, 7], []].
Basically, iter(input_list) creates an iterable of your list so you can fetch the next k values with islice().
You can do this in a loop making use of python's [:#] slice notation:
Let's say the user's input for slicing chunk sizes is stored in a list. They want chunks of 3, 2, 1 and 2, so the user input defining the chunks gets stored into a list that has has [3,2,1,2].
Then, loop through that list and use it to get your slices:
input_list = [0,1,2,3,4,5,6,7]
chunk_list = [3,2,1,2]
output_list = []
for i in chunk_list:
output_list.append(input_list[:i])
input_list = input_list[i:]
print(output_list)
Prints:
[[0, 1, 2], [3, 4], [5], [6, 7]]
Probably you just want to learn about slicing. See Understanding Python's slice notation
To get your example output, you could do
outputList = [inputList[:3], inputList[3:5], inputList[5:6], inputList[6:]]

Is there an equivalent to the C++ pre/postfix operators for use in Python list comprehensions?

I writing a function which populates a list of lists of two elements, where the first element is an element from a different list and the second element is a value which increments.
def list_of_pairs(seq, start):
""" Returns a list of pairs """
>>> list_of_pairs([3, 2, 1], 1)
[ [3, 1], [2, 2], [1, 3] ]
return [[i, start++] for i in seq]
Is there an equivalent to the C++ postfix operators which can be used? Thanks!
Bonus question: Is it more Pythonic to use the list constructor, than to construct the list using square brackets?
Edit: Here is my current (less beautiful) workaround -
def list_of_pairs(seq, start):
""" Returns a list of pairs """
>>> list_of_pairs([3, 2, 1], 1)
[ [3, 1], [2, 2], [1, 3] ]
return [[seq[i], start+i] for i in range(len(seq))]
You may use enumerate() to achieve this. Enumerate return the index along with value while iterating over the list of values. And as per your requirement, you need list of list as [val, index + count]. Below is the sample code to achieve that:
>>> seq = [2, 6, 9]
>>> count = 2
>>> [[val, count+i] for i, val in enumerate(seq)]
[[2, 2], [6, 3], [9, 4]]
You can achieve the same with itertools.count, calling next on the count object for each element of the sequence:
from itertools import count
c = count(start)
lst = [[x, next(c)] for x in seq]
construct the list using square brackets
That's a list comprehension. It's pretty standard and most certainly Pythonic to use list comprehensions for creating lists.
++ and -- have been deliberately excluded from Python, because using them in expressions tends to lead to confusing code and off-by-one errors.
You should use enumerate instead:
def list_of_pairs(seq, start):
return [[elem, i] for i, elem in enumerate(seq, start)]

Python applying dynamic list comprehension (list append)

vals= [1]
for j in xrange(i):
vals.append([k for k in f(vals[j])])
This loop appends values to itself over a loop. If I compress this into a list comprehension, it doesn't work because it doesn't "dynamically" extend vals using itself on each iteration -- it processes vals as it is originally framed.
Is there a way to do a one line list comprehension that dynamically appends like this? Based on my research, it looks like maybe I am looking for a reduce function? (the equivalent of a fold)
You can indeed use reduce for this, using the initial list as the third parameter.
>>> def f(lst):
... return [x+1 for x in lst] + [len(lst)]
>>> reduce(lambda lst, i: lst + [f(lst[i])], range(5), [[1]])
[[1], [2, 1], [3, 2, 2], [4, 3, 3, 3], [5, 4, 4, 4, 4], [6, 5, 5, 5, 5, 5]]
(Note that the initial list should probably be [[1]], not [1], otherwise you are passing a number to f in the first iteration, but a list in all following iterations.)
Also note that concerning performance your original loop is probably a bit faster, as the reduce basically has to create two new lists in each iteration, while you just have to append to a list. Personally, I would go with a variation of the loop, removing the (probably useless) inner list comprehension and using [-1] to make clear that you are always using the previous result.
vals = [[1]]
for _ in xrange(n):
vals.append(f(vals[-1]))

Categories

Resources