Related
I want to multiply a list of list with a list using python 3 suppose that the list of list is of name L as follows:
L = [[45.909221207388235, 84.41069326628269], [80.6591435966521, 47.93257841035172]]
and the second list is:
S = [0.002, 0.001]
the multiplication should be: L[0][0]* S[0] and L[0][1]* S[0] then L[1][0]* S[1] and L[1][1]* S[1].
I tried the zip method :
[a*b for x,y in zip(S,L) for a,b in zip(x,y)]
But an error appears: zip argument 1 must support iteration.
the second trial was using map(lambda):
map(lambda x,y:x*y,L,S)
but the obtained results were wrong:
[9.181844241477647e-05, 0.00016882138653256538, 0.0001613182871933042, 9.586515682070343e-05]
the correct values are:
[0.09181844241477648, 0.1688213865325654, 0.0806591435966521, 0.047932578410351714]
You want to use zip, but not twice:
>>> L = [[45.909221207388235, 84.41069326628269], [80.6591435966521, 47.93257841035172]]
>>> S = [0.002, 0.001]
>>> [n*x for n, sub in zip(S, L) for x in sub]
[0.09181844241477648, 0.1688213865325654, 0.0806591435966521, 0.047932578410351714]
>>>
So, you want to pair up every number with every sublist, then multiply every number in the sublist by that main number.
Note, just in case you are using numpy (I don't think you are, and I don't think it would be reasonable to use numpy just for this), and S and L are numpy.ndarray objects, i.e.:
>>> S = np.array(S)
>>> L = np.array(L)
Then you probably just want:
>>> (S*L).ravel()
array([0.09181844, 0.08441069, 0.16131829, 0.04793258])
If I understand corresly you want to multiply each column in L by the corresponding value of S:
L = [[45.909221207388235, 84.41069326628269],
[80.6591435966521, 47.93257841035172]]
S = [0.002, 0.001]
R = [ [s*n for n in row] for s,row in zip(S,L) ]
output:
print(R)
[ [0.09181844241477648, 0.1688213865325654],
[0.0806591435966521, 0.047932578410351714]]
You should have given an example with a different number of rows than columns to make this clearer
Is there a way to use count() where you are looking for a specific value in the nested list and not caring about the rest?
lst = [[1,6],[1,4],[3,4],[1,2]]
X = 1
lst.count([X, _ ])
This would return a count of 3, since there are three nested lists that have a 1 in the first index.
Is there a way to do this?
Use some sneaky sum() hacks:
sum(k[0] == X for k in your_list)
I.e.
>>> X = 1
>>> your_list = [[1,6],[1,4],[3,4],[1,2]]
>>> sum(k[0] == X for k in your_list)
3
why?
The section: k[0] == X for k in your_list is a generator expression that yields True for each element in your_list which has first element equal to your X. The sum() function takes the values and treats a True as a 1.
Look at the length of a filtered list:
my_list = [[1,6][1,4][3,4][1,2]]
X = 1
len([q for q in my_list if q[0] == X])
Or, if you prefer to use count, then make a list of the items you do care about:
[q[0] for q in my_list].count(X)
You can do len(filter(lambda x: x[0] == 1, lst))
But be careful, if your list contains an element that is not a list (or an empty list) it will throw an exception! This could be handled by adding two additional conditions
len(filter(lambda x: type(x) == list and len(x) > 0 and x[0] == 1, lst))
Counting how often one value occurs in the first position requires a full pass over the list, so if you plan to use the potential countfunction(inputlist, target) more than once on the same list, it's more efficient to build a dictionary holding all the counts (also requiring one pass) which you can subsequently query with O(1).
>>> from collections import Counter
>>> from operator import itemgetter
>>>
>>> lst = [[1,6],[1,4],[3,4],[1,2]]
>>> c = Counter(map(itemgetter(0), lst))
>>> c[1]
3
>>> c[3]
1
>>> c[512]
0
Others have shown good ways to approach this problem using python built-ins, but you can use numpy if what you're actually after is fancy indexing.
For example:
import numpy as np
lst = np.array([[1,6],[1,4],[3,4],[1,2]])
print(lst)
#array([[1, 6],
# [1, 4],
# [3, 4],
# [1, 2]])
In this case lst is a numpy.ndarray with shape (4,2) (4 rows and 2 columns). If you want to count the number of rows where the first column (index 0) is equal to X, you can write:
X = 1
print((lst[:,0] == X).sum())
#3
The first part lst[:,0] means grab all rows and only the first index.
print(lst[:,0])
#[1 1 3 1]
Then you check which of these is equal to X:
print(lst[:,0]==X)
#[ True True False True]
Finally sum the resultant array to get the count. (There is an implicit conversion from bool to int for the sum.)
Given a list of integers, I want to check a second list and remove from the first only those which can not be made from the sum of two numbers from the second. So given a = [3,19,20] and b = [1,2,17], I'd want [3,19].
Seems like a a cinch with two nested loops - except that I've gotten stuck with break and continue commands.
Here's what I have:
def myFunction(list_a, list_b):
for i in list_a:
for a in list_b:
for b in list_b:
if a + b == i:
break
else:
continue
break
else:
continue
list_a.remove(i)
return list_a
I know what I need to do, just the syntax seems unnecessarily confusing. Can someone show me an easier way? TIA!
You can do like this,
In [13]: from itertools import combinations
In [15]: [item for item in a if item in [sum(i) for i in combinations(b,2)]]
Out[15]: [3, 19]
combinations will give all possible combinations in b and get the list of sum. And just check the value is present in a
Edit
If you don't want to use the itertools wrote a function for it. Like this,
def comb(s):
for i, v1 in enumerate(s):
for j in range(i+1, len(s)):
yield [v1, s[j]]
result = [item for item in a if item in [sum(i) for i in comb(b)]]
Comments on code:
It's very dangerous to delete elements from a list while iterating over it. Perhaps you could append items you want to keep to a new list, and return that.
Your current algorithm is O(nm^2), where n is the size of list_a, and m is the size of list_b. This is pretty inefficient, but a good start to the problem.
Thee's also a lot of unnecessary continue and break statements, which can lead to complicated code that is hard to debug.
You also put everything into one function. If you split up each task into different functions, such as dedicating one function to finding pairs, and one for checking each item in list_a against list_b. This is a way of splitting problems into smaller problems, and using them to solve the bigger problem.
Overall I think your function is doing too much, and the logic could be condensed into much simpler code by breaking down the problem.
Another approach:
Since I found this task interesting, I decided to try it myself. My outlined approach is illustrated below.
1. You can first check if a list has a pair of a given sum in O(n) time using hashing:
def check_pairs(lst, sums):
lookup = set()
for x in lst:
current = sums - x
if current in lookup:
return True
lookup.add(x)
return False
2. Then you could use this function to check if any any pair in list_b is equal to the sum of numbers iterated in list_a:
def remove_first_sum(list_a, list_b):
new_list_a = []
for x in list_a:
check = check_pairs(list_b, x)
if check:
new_list_a.append(x)
return new_list_a
Which keeps numbers in list_a that contribute to a sum of two numbers in list_b.
3. The above can also be written with a list comprehension:
def remove_first_sum(list_a, list_b):
return [x for x in list_a if check_pairs(list_b, x)]
Both of which works as follows:
>>> remove_first_sum([3,19,20], [1,2,17])
[3, 19]
>>> remove_first_sum([3,19,20,18], [1,2,17])
[3, 19, 18]
>>> remove_first_sum([1,2,5,6],[2,3,4])
[5, 6]
Note: Overall the algorithm above is O(n) time complexity, which doesn't require anything too complicated. However, this also leads to O(n) extra auxiliary space, because a set is kept to record what items have been seen.
You can do it by first creating all possible sum combinations, then filtering out elements which don't belong to that combination list
Define the input lists
>>> a = [3,19,20]
>>> b = [1,2,17]
Next we will define all possible combinations of sum of two elements
>>> y = [i+j for k,j in enumerate(b) for i in b[k+1:]]
Next we will apply a function to every element of list a and check if it is present in above calculated list. map function can be use with an if/else clause. map will yield None in case of else clause is successful. To cater for this we can filter the list to remove None values
>>> list(filter(None, map(lambda x: x if x in y else None,a)))
The above operation will output:
>>> [3,19]
You can also write a one-line by combining all these lines into one, but I don't recommend this.
you can try something like that:
a = [3,19,20]
b= [1,2,17,5]
n_m_s=[]
data=[n_m_s.append(i+j) for i in b for j in b if i+j in a]
print(set(n_m_s))
print("after remove")
final_data=[]
for j,i in enumerate(a):
if i not in n_m_s:
final_data.append(i)
print(final_data)
output:
{19, 3}
after remove
[20]
I have a list of 50 numbers, [0,1,2,...49] and I would like to create a list of tuples without duplicates, where i define (a,b) to be a duplicate of (b,a). Similarly, I do not want tuples of the form (a,a).
I have this:
pairs = set([])
mylist = range(0,50)
for i in mylist:
for j in mylist:
pairs.update([(i,j)])
set((a,b) if a<=b else (b,a) for a,b in pairs)
print len(pairs)
>>> 2500
I get 2500 whereas I expect to get, i believe, 1225 (n(n-1)/2).
What is wrong?
You want all combinations. Python provides a module, itertools, with all sorts of combinatorial utilities like this. Where you can, I would stick with using itertool, it almost certainly faster and more memory efficient than anything you would cook up yourself. It is also battle-tested. You should not reinvent the wheel.
>>> import itertools
>>> combs = list(itertools.combinations(range(50),2))
>>> len(combs)
1225
>>>
However, as others have noted, in the case where you have a sequence (i.e. something indexable) such as a list, and you want N choose k, where k=2 the above could simply be implemented by a nested for-loop over the indices, taking care to generate your indices intelligently:
>>> result = []
>>> for i in range(len(numbers)):
... for j in range(i + 1, len(numbers)):
... result.append((numbers[i], numbers[j]))
...
>>> len(result)
1225
However, itertool.combinations takes any iterable, and also takes a second argument, r which deals with cases where k can be something like 7, (and you don't want to write a staircase).
Your approach essentially takes the cartesian product, and then filters. This is inefficient, but if you wanted to do that, the best way is to use frozensets:
>>> combinations = set()
>>> for i in numbers:
... for j in numbers:
... if i != j:
... combinations.add(frozenset([i,j]))
...
>>> len(combinations)
1225
And one more pass to make things tuples:
>>> combinations = [tuple(fz) for fz in combinations]
Try This,
pairs = set([])
mylist = range(0,50)
for i in mylist:
for j in mylist:
if (i < j):
pairs.append([(i,j)])
print len(pairs)
problem in your code snippet is that you filter out unwanted values but you don't assign back to pairs so the length is the same... also: this formula yields the wrong result because it considers (20,20) as valid for instance.
But you should just create the proper list at once:
pairs = set()
for i in range(0,50):
for j in range(i+1,50):
pairs.add((i,j))
print (len(pairs))
result:
1225
With that method you don't even need a set since it's guaranteed that you don't have duplicates in the first place:
pairs = []
for i in range(0,50):
for j in range(i+1,50):
pairs.append((i,j))
or using list comprehension:
pairs = [(i,j) for i in range(0,50) for j in range(i+1,50)]
I'm currently writing a little script in python (2.x), and there's a portion of the code that I'd like to improve without knowing how to do so.
I have a list of lists that looks like the following:
my_list = [["abc",1,2,"def"],["ghi",4,5,"klm"],["nop",6,7,"qrs"]]
I need to get the sum of all the integers at the index 1 and the sum of all the integers at the index 2. To do so, I currently have:
sum1, sum2 = 0, 0
for i in my_list:
sum1 += i[1]
sum2 += i[2]
What could be a more pythonic way to do that? Maybe using reduce and a lambda function or something?
A more pythonic way to do that would be using the sum function along with the for ... in ... generator and do all the work in a single line, like this:
sum1, sum2 = sum(x[1] for x in my_list), sum(x[2] for x in my_list)
The most Pythonic would probably be list comprehensions:
my_list = [["abc",1,2,"def"],["ghi",4,5,"klm"],["nop",6,7,"qrs"]]
Summations:
sum1 = sum(l[1] for l in my_list)
sum2 = sum(l[2] for l in my_list)
Which returns:
sum1 = 11
sum2 = 14
You could do sum(x[1] for x in in my_list), sum(x[2] for x in my_list) if you don't mind looping twice.
or reduce(lambda acc, l: (acc[0] + l[1], acc[1] + l[2]), my_list, (0, 0)) if you want to do it both at once. This will return a tuple with the sum of [1] on the first element, and [2] on the second
You can use zip and list comprehension
>>> lst = [["abc",1,2,"def"],["ghi",4,5,"klm"],["nop",6,7,"qrs"]]
>>> [sum(i) for i in list(zip(*lst))[1:3]]
[11, 14]
Or use zip and islice class from itertools
>>> from itertools import islice
>>> [sum(i) for i in islice(zip(*lst), 1, 3)]
[11, 14]
Here's a one liner that doesn't use a generator expression. Use zip plus unpacking to transpose the list, then run sum on all the numeric columns using map.
>>> map(sum, zip(*my_list)[1:-1])
[11, 14]
Unfortunately it's a little wordier in 3.X since you can't slice a zip object.
a,b = map(sum, list(zip(*my_list))[1:-1])
You can use reduce but, since the elements in your sequence are lists, you'll need to set an initial value of 0. In Example:
reduce(lambda total, list: total+list[1], my_list, 0) # integers at index 1
reduce(lambda total, list: total+list[2], my_list, 0) # integers at index 2