Maximum sum of sub list in a list of lists - python

Making my first steps in Python.
I have a list of lists and i'm trying to return the sub list with largest sum of all sub lists.
For now I just have the max sum itself.
Ex: this code returns 18, but I need to return [3,3,3,3,3,3]
Any directions?
Thanks
def find_biggest(lst):
inner_list_sum = []
for i in range(len(lst)):
inner_list_sum.append(sum(lst[i])) # list of elements sums
return max(inner_list_sum) # I actually need the element itself...not the max sum
print(find_biggest([[1,2,3,4], [1,2,3,3], [1,1], [3,3,3,3,3,3]]))

Use max with key=sum
Ex:
data = [[1,2,3,4], [1,2,3,3], [1,1], [3,3,3,3,3,3]]
print(max(data, key=sum))
Output:
[3, 3, 3, 3, 3, 3]

OK
Since I'm not allowed to use (max(data, key=sum)).
I did this not very elegant code, but it was accepted a correct answer
def find_biggest(lst):
inner_list_sum = []
for i in range(len(lst)):
inner_list_sum.append(sum(lst[i])) # list of elements sums
max_element=max(inner_list_sum)
seq_index= inner_lis

import functools
def find_biggest(lst):
return functools.reduce(lambda x, y : x if sum(x) > sum(y) else y, lst)
Here, the used lambda expression is the function equivalent to find the greatest sum and lst is iterable.
Please note: reduce will directly work for python2, you need to import functools
for python3only.
Using functools.reduce

Related

Summing each element of two arrays

I have two arrays and want to sum each element of both arrays and find the maximum sum.
I have programmed it like this:
sum = []
for element in arrayOne:
sum.append(max([item + element for item in arrayTwo]))
print max(sum)
is there any better way to achieve this?
You can use numpy.
import numpy as np
a = np.array(arrayOne)
b = np.array(arrayTwo)
max = max(a + b)
print(max)
Use itertools.product with max:
from itertools import product
print(max(sum(x) for x in product(arrayOne, arrayTwo)))
Or using map:
print(max(map(sum,product(arrayOne, arrayTwo))))
max_sum = max(map(sum, zip(arrayOne, arrayTwo)))
Upd.
If you need max from sum of all elements in array:
max_sum = max(sum(arrayOne), sum(arrayTwo))
If arrayOne and arrayTwo are nested lists ([[1, 2], [3, 3], [3, 5], [4, 9]]) and you need to find element with max sum:
max_sum = max(map(sum, arrayOne + arrayTwo))
P. S. Next time, please, provide examples of input and output to not let us guess what do you need.
To find a maximum of all pairwise sums of elements of two arrays of lengths n and m respectively one can just
max(arrayOne) + max(arrayTwo)
which would perform at worst in O(max(n, m)) instead of O(n*m) when going over all the combinations.
However, if, for whatever reason, it is necessary to iterate over all the pairs, the solution might be
max(foo(one, two) for one in arrayOne for two in arrayTwo)
Where foo can be any function of two numeric parameters outputting a number (or an object of any class that implements ordering).
By the way, please avoid redefining built-ins like sum in your code.

Equivalent of List Comprehension Using Map and Filter

I want to write this code using a map and/or a filter function. It returns the indices of items in a list provided the sum up to a target
I have used list comprehension for this but can't see how to get the second for loop into the map/filter function. I'm not sure about the syntax to use If I define my own function for the function argument of the map/filter function
num = [2,5,7,11,6,15,3,4]
tgt= 9
[num.index(x) for x in num for y in num if x + y == tgt]
Results:
[0, 1, 2, 4, 6, 7]
Since both filter and map work over individual items in a sequence, you would have to view your logic from the perspective of each item in the list, rather than a combination of items, and that means you need to rephrase the expressions used in your list comprehension as functions of individual items. Instead of the filter condition x + y == tgt, therefore, it is beneficial to view it as x == tgt - y, where y also has to be an item in the num list, so that your list comprehension can be rewritten as:
[num.index(x) for x in num if x in {tgt - y for y in num}]
With this equivalent list comprehension, it then becomes clear that to implement the filter condition would need to make a set by mapping each item in num to its difference with tgt, which can be done with the tgt.__sub__ method, and test each item x in num if it is a member of the set, which can be done with the set's __contains__ method, and finally, map the filtered sequence to num.index to output the index of each matching item:
list(map(num.index, filter(set(map(tgt.__sub__, num)).__contains__, num)))
This returns:
[0, 1, 2, 4, 6, 7]
Try this! You can use itertools.product to get the combinations of each. Then filter the list of combinations for items whose sum is tgt. Then map a lambda to those results to get the index of the first item in those combinations.
list(map(lambda x: num.index(x[0]), (filter(lambda x: sum(x) == tgt, itertools.product(num, repeat=2)))))
The double loop can be code as a itertools.product:
>>> list(map(lambda x: num.index(x[0]), filter(lambda x: sum(x) == tgt, itertools.product(num, num))))
[0, 1, 2, 4, 6, 7]
Lets chop the code:
filter(lambda x: sum(x) == tgt, itertools.product(num, num))
itertools.product returns an iterator of tuples whith the elements in num, being (x, y) similar to the nested loop you use.
over we filter which of those tuples summation is equal to tgt, using sum is the better choice here, but notice it would be the same as x[0] + x[1] (remember we are giving tuples like (2, 2) to that function).
Once we have that filtered we apply for each of those tuples that remain the function num.index, since we have tuples we only need to use one of the values, remember the first one matches the nested for loop x hence num.index(x[0])
Repeatedly calling num.index is very inefficient. Each time you find a number that satisfies your condition, the call to index requires a sequential scan of the list.
Instead turn your loop over the indices in the list. Make the comparison by indexing the array (random access), which will be much more efficient.
As others have pointed out, you can use itertools.product but instead of the product of num with itself, do the self product of range(len(num)).
Using map and filter:
from operator import itemgetter
from itertools import product
res = map(
itemgetter(0),
filter(
lambda c: num[c[0]]+num[c[1]] == tgt,
product(range(len(num)),range(len(num)))
)
)
print(list(res))
#[0, 1, 2, 4, 6, 7]
The inner filter is filtering all pairs of numbers between 0 and the length of num minus one, for which the values at num at those corresponding indices is equal to the target. Since product returns a pair of indices and you are only interested in the first value, map the result of the filter with itemgetter(0) to get the first element.
More compactly as a list comprehension:
[i for i, j in product(range(len(num)), range(len(num))) if num[i] + num[j] == tgt]

Python - reduce ,two dimensional array

I 'm trying to use reduce on two-dimensional array which consists of coordinates.I don't have a lot of experience with reduce .I have a function called func and I have to apply this function to each element of the array. For example:
func=lambda x:x-1
array=[[5,9],[10,3]]
reduce (lambda x,y: ...,array)
OUTPUT should be -> [[4,8],[9,2]]
I just decrement each element by 1 . Thanks.
reduce takes a function of two arguments and applies it cumulatively to the elements of a sequence - but all you want to do is subtract one from every element of every sublist, so I'm not sure why you would want to use reduce here.
I suggest this list comprehension:
>>> lst = [[5,9],[10,3]]
>>> [[x-1 for x in sub] for sub in lst]
[[4, 8], [9, 2]]
Or if you want to use your lambda function:
>>> [map(lambda x: x-1, sub) for sub in lst]
[[4, 8], [9, 2]]
I find the first one to be more readable, though.
you don't need to use reduce to decrease each element's value.
Try using map
arr = map( lambda x:[x[0]-1,x[1]-1],arr)

using python itertools to manage nested for loops

I am trying to use itertools.product to manage the bookkeeping of some nested for loops, where the number of nested loops is not known in advance. Below is a specific example where I have chosen two nested for loops; the choice of two is only for clarity, what I need is a solution that works for an arbitrary number of loops.
This question provides an extension/generalization of the question appearing here:
Efficient algorithm for evaluating a 1-d array of functions on a same-length 1d numpy array
Now I am extending the above technique using an itertools trick I learned here:
Iterating over an unknown number of nested loops in python
Preamble:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
At the end of the above itertools loop, I have a 12-element, 1-d array of functions, func_table, each element having been built from the trivial_functional.
Question:
Suppose I am given a pair of integers, (i_1, i_2), where these integers are to be interpreted as the indices of idx1 and idx2, respectively. How can I use itertools.product to determine the correct corresponding element of the func_table array?
I know how to hack the answer by writing my own function that mimics the itertools.product bookkeeping, but surely there is a built-in feature of itertools.product that is intended for exactly this purpose?
I don't know of a way of calculating the flat index other than doing it yourself. Fortunately this isn't that difficult:
def product_flat_index(factors, indices):
if len(factors) == 1: return indices[0]
else: return indices[0] * len(factors[0]) + product_flat_index(factors[1:], indices[1:])
>> product_flat_index(joint, (2, 1))
9
An alternative approach is to store the results in a nested array in the first place, making translation unnecessary, though this is more complex:
from functools import reduce
from operator import getitem, setitem, itemgetter
def get_items(container, indices):
return reduce(getitem, indices, container)
def set_items(container, indices, value):
c = reduce(getitem, indices[:-1], container)
setitem(c, indices[-1], value)
def initialize_table(lengths):
if len(lengths) == 1: return [0] * lengths[0]
subtable = initialize_table(lengths[1:])
return [subtable[:] for _ in range(lengths[0])]
func_table = initialize_table(list(map(len, joint)))
for items in product(*map(enumerate, joint)):
f = trivial_functional(*map(itemgetter(1), items))
set_items(func_table, list(map(itemgetter(0), items)), f)
>>> get_items(func_table, (2, 1)) # same as func_table[2][1]
<function>
So numerous answers were quite useful, thanks to everyone for the solutions.
It turns out that if I recast the problem slightly with Numpy, I can accomplish the same bookkeeping, and solve the problem I was trying to solve with vastly improved speed relative to pure python solutions. The trick is just to use Numpy's reshape method together with the normal multi-dimensional array indexing syntax.
Here's how this works. We just convert func_table into a Numpy array, and reshape it:
func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
Now func_table can be used to return the correct function not just for a single 2d point, but for a full array of 2d points:
dim1_pts = [3,1,2,1,3,3,1,3,0]
dim2_pts = [0,1,2,1,2,0,1,2,1]
func_array = func_table[dim1_pts, dim2_pts]
As usual, Numpy to the rescue!
This is a little messy, but here you go:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [enumerate(idx1), enumerate(idx2)]
func_map = {}
for indexes, items in map(lambda x: zip(*x), product(*joint)):
f = trivial_functional(*items)
func_map[indexes] = f
print(func_map[(2, 0)](5)) # 40 = (3+5)*5
I'd suggest using enumerate() in the right place:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
From what I understood from your comments and your code, func_table is simply indexed by the occurence of a certain input in the sequence. You can access it back again using:
for index, items in enumerate(product(*joint)):
# because of the append(), index is now the
# position of the function created from the
# respective tuple in join()
func_table[index](some_value)

Remove empty string from list

I just started Python classes and I'm really in need of some help. Please keep in mind that I'm new if you're answering this.
I have to make a program that takes the average of all the elements in a certain list "l". That is a pretty easy function by itself; the problem is that the teacher wants us to remove any empty string present in the list before doing the average.
So when I receive the list [1,2,3,'',4] I want the function to ignore the '' for the average, and just take the average of the other 4/len(l). Can anyone help me with this?
Maybe a cycle that keeps comparing a certain position from the list with the '' and removes those from the list? I've tried that but it's not working.
You can use a list comprehension to remove all elements that are '':
mylist = [1, 2, 3, '', 4]
mylist = [i for i in mylist if i != '']
Then you can calculate the average by taking the sum and dividing it by the number of elements in the list:
avg = sum(mylist)/len(mylist)
Floating Point Average (Assuming python 2)
Depending on your application you may want your average to be a float and not an int. If that is the case, cast one of these values to a float first:
avg = float(sum(mylist))/len(mylist)
Alternatively you can use python 3's division:
from __future__ import division
avg = sum(mylist)/len(mylist)
You can use filter():
filter() returns a list in Python 2 if we pass it a list and an iterator in Python 3. As suggested by #PhilH you can use itertools.ifilter() in Python 2 to get an iterator.
To get a list as output in Python 3 use list(filter(lambda x:x != '', lis))
In [29]: lis = [1, 2, 3, '', 4, 0]
In [30]: filter(lambda x:x != '', lis)
Out[30]: [1, 2, 3, 4, 0]
Note to filter any falsy value you can simply use filter(None, ...):
>>> lis = [1, 2, 3, '', 4, 0]
>>> filter(None, lis)
[1, 2, 3, 4]
The other answers show you how to create a new list with the desired element removed (which is the usual way to do this in python). However, there are occasions where you want to operate on a list in place -- Here's a way to do it operating on the list in place:
while True:
try:
mylist.remove('')
except ValueError:
break
Although I suppose it could be argued that you could do this with slice assignment and a list comprehension:
mylist[:] = [i for i in mylist if i != '']
And, as some have raised issues about memory usage and the wonders of generators:
mylist[:] = (i for i in mylist if i != '')
works too.
itertools.ifilterfalse(lambda x: x=='', myList)
This uses iterators, so it doesn't create copies of the list and should be more efficient both in time and memory, making it robust for long lists.
JonClements points out that this means keeping track of the length separately, so to show that process:
def ave(anyOldIterator):
elementCount = 0
runningTotal = 0
for element in anyOldIterator:
runningTotal += element
elementCount += 1
return runningTotal/elementCount
Or even better
def ave(anyOldIterator):
idx = None
runningTotal = 0
for idx,element in enumerate(anyOldIterator):
runningTotal += element
return runningTotal/(idx+1)
Reduce:
def ave(anyOldIterator):
pieces = reduce(lambda x,y: (y[0],x[1]+y[1]), enumerate(anyOldIterator))
return pieces[1]/(pieces[0]+1)
Timeit on the average of range(0,1000) run 10000 times gives the list comprehension a time of 0.9s and the reduce version 0.16s. So it's already 5x faster before we add in filtering.
You can use:
alist = ['',1,2]
new_alist = filter(None, alist)
new_alist_2 = filter(bool, alist)
Result:
new_alist = [1,2]
new_alist_2 = [1,2]
mylist = [1, 2, 3, '', 4]
newlist = []
for i in mylist:
try:
newlist.append(int(i))
except ValueError:
pass
avg = sum(newlist)/len(newlist)
'' is equivalent to False. If we filter the 0 case out (because 0 is equivalent to False), we can use list comprehension :
[x for x in a if x or x == 0]
Or if we strictly want to filter out empty strings :
[x for x in a if x != '']
This may not be the fastest way.
Edit, added some bench results comparing with the other solutions (not for the sake of comparing myself to others, but I was curious too of what method was the fastest)
ragsagar>
6.81217217445
pistache>
1.0873541832
cerealy>
1.07090902328
Matt>
1.40736508369
Ashwini Chaudhary>
2.04662489891
Phil H (just the generator) >
0.935978889465
Phil H with list() >
3.58926296234
I made the script quickly, using timeit(), I used [0,1,2,0,3,4,'',5,8,0,'',4] as the list. I ran multiple tests, results did not vary.
NOTE: I'm not trying to put my solution on top using speed as a criteria. I know OP didn't specifically ask for speed, but I was curious and maybe some other are.

Categories

Resources