How do i write a list comprehension in python with an inclusion of a
count = count + 1?
print sum([info[count]["count"] for i in info])
# This is the working loop:
count = 0
lst = []
for i in info:
num = info[count]["count"]
# print num
count = count + 1
lst.append(num)
print sum(lst)
>>> a = ['a','b','c']
>>> v = ['a','e','i','o','u']
>>> len(a)
3
>>> sum([1 for x in a if x in v])
2
I do not follow why you use i in i in info together with count. If info is enumerable and enumerating has the same effect as accessing with a zero offset index (like you seem to do with count, you can rewrite your loop like:
lst = []
for infoi in info:
num = infoi["count"]
# print num
lst.append(num)
print sum(lst)
Now you can convert this to the following list comprehension:
sum([infoi["count"] for infoi in info])
Finally you do not need to materialize the comprehension to a list, sum can work on a generator:
sum(infoi["count"] for infoi in info)
This can be more efficient, since you will not construct a list first with all the values: sum will enumerate over all items and thus will result in constant memory usage.
Related
I was solving this leetcode problem - https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
I solved it easily by using nested for loops but list comprehensions have always intrigued me. Ive spent a lot of time to make that one liner work but I always get some syntax error.
here's the solution:
count = 0
ans = []
for i in nums:
for j in nums:
if i > j:
count = count + 1
ans.append(count)
count = 0
return ans
these were the ones so far I think shouldve worked:
return [count = count + 1 for i in nums for j in nums if i > j]
return [count for i in nums for j in nums if i > j count = count + 1]
return [count:= count + 1 for i in nums for j in nums if i > j]
Ill also be happy if there's some resource or similar to put it together, Ive been searching the python docs but didnt find something that'll help me
I will transform the code step by step in order to show the thought process.
First: we don't care what the value of count is afterward, but we need it to be 0 at the start of each inner loop. So it is simpler logically to set it there, rather than outside and then also at the end of the inner loop:
ans = []
for i in nums:
count = 0
for j in nums:
if i > j:
count = count + 1
ans.append(count)
return ans
Next, we focus on the contents of the loop:
count = 0
for j in nums:
if i > j:
count = count + 1
ans.append(count)
A list comprehension is not good at math; it is good at producing a sequence of values from a source sequence. The transformation we need to do here is to put the actual elements into our "counter" variable1, and then figure out how many there are (in order to append to ans). Thus:
smaller = []
for j in nums:
if i > j:
smaller.append(j)
ans.append(len(smaller))
Now that the creation of smaller has the right form, we can replace it with a list comprehension, in a mechanical, rule-based way. It becomes:
smaller = [j for j in nums if i > j]
# ^ ^^^^^^^^^^^^^ ^^^^^^^^
# | \- the rest of the parts are in the same order
# \- this moves from last to first
# and then we use it the same as before
ans.append(len(smaller))
We notice that we can just fold that into one line; and because we are passing a single comprehension argument to len we can drop the brackets2:
ans.append(len(j for j in nums if i > j))
Good. Now, let's put that back in the original context:
ans = []
for i in nums:
ans.append(len(j for j in nums if i > j))
return ans
We notice that the same technique applies: we have the desired form already. So we repeat the procedure:
ans = [len(j for j in nums if i > j) for i in nums]
return ans
And of course:
return [len(j for j in nums if i > j) for i in nums]
Another popular trick is to put a 1 in the output for each original element, and then sum them. It's about the same either way; last I checked the performance is about the same and I don't think either is clearer than the other.
Technically, this produces a generator expression instead. Normally, these would be surrounded with () instead of [], but a special syntax rule lets you drop the extra pair of () when calling a function with a single argument that is a generator expression. This is especially convenient for the built-in functions len and sum - as well as for any, all, max, min and (if you don't need a custom sort order) sorted.
Hmm, three people write sum solutions but every single one does sum(1 for ...). I prefer this:
[sum(j < i for j in nums) for i in nums]
Instead of trying to advance an external counter, try adding ones to your list and then sum it:
for example:
nums = [1,2,3,4,5]
target = 3
print(sum(1 for n in nums if n < target))
Using counter inside the list comprehension creates the challenge of resetting it's value, each iteration of the first loop.
This can be avoided by filtering, and summing, in the second loop:
You use the first loop to iterate over the values of nums array.
return [SECOND_LOOP for i in nums]
You use the second loop, iterating over all elements of nums array. You filter in the elements that are smaller than i, the current element in the first loop, with if i < j, and evaluating 1 for each of them. Finally, you sum all the 1s generated:
sum(1 for j in nums if i > j)
You get the number of values that meet the requirements, by the list comprehension of the first loop:
return [sum(1 for j in nums if i > j) for i in nums]
This solution has been checked & validated in LeetCode.
You need a slightly different approach for the inner loop than a list comprehension. Instead of repeatedly appending a value to a list you need to repeatedly add a value to a variable.
This can be done in a functional way by using sum and a generator expression:
count = 0
# ...
for j in nums:
if i > j:
count = count + 1
can be replaced by
count = sum(1 for j in nums if i > j)
So that we now have this:
ans = []
for i in nums:
count = sum(1 for j in nums if i > j)
ans.append(count)
return ans
This pattern can in fact be replaced by a list comprehension:
return [sum(1 for j in nums if i > j) for i in nums]
Alternative Solution
We can also use the Counter from collections:
class Solution:
def smallerNumbersThanCurrent(self, nums):
count_map = collections.Counter(nums)
smallers = []
for index in range(len(nums)):
count = 0
for key, value in count_map.items():
if key < nums[index]:
count += value
smallers.append(count)
return smallers
I am learning python since last few days, I have read a problem on a site where they provided the solution with some built-in function. I have tried to do it without it, could you please check if i have done this correctly or should it be done with some other logic.
Problem: Write a Python program to find the list in a list of lists whose sum of elements is the highest.
Solution:
Code
num = [1,2,3], [4,5,6], [10,11,12], [7,8,9], [87,6,9], [87,7,9]
def func(l):
#function will return the element (list) whose sum is greater
res = []
flag = 0
for index, items in enumerate(l):
total = 0
for item in items:
total = total + item
res.append(total)
if total > res[index]:
flag = index
return l[flag]
#function call
print(func(num))
No, your code is not correct. The problem is with the res list. Not sure that that's supposed to do, but you just keep appending items and then check the item at the index of the current outer loop. Instead, you should just keep track of the best_sum seen so far. Also, I'd suggest using better variable names.
def func(l):
best_sum = 0
best_index = 0
for index, items in enumerate(l):
total = 0
for item in items:
total = total + item
if total > best_sum:
best_index = index
best_sum = total
return l[best_index]
num = [1,2,3], [4,5,6], [10,11,12], [7,8,9], [87,6,9], [87,7,9], [1,1,1]
print(func(num))
Of course, using builtins max and sum, you can just do
print(max(num, key=sum))
If you want the actual sum, you could take the max of the sum of each list.
m = max(sum(x) for x in num)
If you want the list:
for x in num:
if sum(x) == m:
print(x)
For example, I have two lists:
A=['a','b','c']
B=['a','a','b','c']
I want my output to look like:
[2,1,1]
Here is what I tried:
P=np.ndarray(shape=3, dtype=int)
count=0
d=0
for i in A:
for j in B:
if i==j:
count+=1
P[d]=count
d+=1
But I am getting
[2,3,4]
as output. What is going wrong?
Just use count method:
A=['a','b','c']
B=['a','a','b','c']
[B.count(x) for x in A]
The methods as suggested by #CarlesMitjans or #WillenVanOnsem are better solutions than this, but the reason your method does not work is that you need to initialise your count variable inside the first loop (and also indent the d+=1 line):
P = np.ndarray(shape=3, dtype=int)
count = 0
d = 0
for i in A:
count = 0
for j in B:
if i == j:
count += 1
P[d] = count
d += 1
which gives:
>>> P
array([2, 1, 1])
If the elements are hashable, you can simply use a counter you then transform back into a list. Like:
from collections import Counter
ctr = Counter(B)
result = [ctr[x] for x in A]
This generates:
>>> [ctr[x] for x in A]
[2, 1, 1]
This works in O(|A|+|B|) with |A| the numbers in A and |B| the numbers in B (given dictionary lookup works in O(1), which is nearly always the case).
If the elements can not be hashed (for instance lists, dictionaries, objects,...), then you can use #CharlesMitjans answer, which runs in O(|A|×|B|) (which tends to be less efficient, but then you cannot take advantage of hashing).
In this script I have used both list comprehension and for. I need to replace for loop with comprehension and add this solve inside list comprehension.
How can add
for i in k:
count_list.append(l.count(i))
inside this block
pairs = [int(pair/2) for pair in count_list if int(pair/2) != 0]
My code:
def sockMerchant(ar):
l = ar
k = set(l)
count_list = []
for i in k:
count_list.append(l.count(i))
pairs = [int(pair/2) for pair in count_list if int(pair/2) != 0]
return sum(pairs)
n = int(input().strip())
ar = list(map(int, input().strip().split(' ')))
result = sockMerchant(ar)
print(result)
You should not be using a list comprehension at all, nor the for loop you have now. The loop is inefficient; by using list.count() you are traversing the whole list l for every unique value, creating a O(N^2) loop.
Use a collections.Counter() object instead and count in O(N) time:
from collections import Counter
def sockMerchant(ar):
counts = Counter(ar)
return sum(count//2 for count in counts.values())
or even
def sockMerchant(ar):
return sum(count//2 for count in Counter(ar).values())
if you insist on a single line.
Note that sum() doesn't mind a few 0 values here and there, so I removed the if test for single 'socks'. Also, I used the // floor division operator rather than turning the floating point result of dividing by 2 back into an integer.
I am trying to write a function that will add all of the numbers in a list that do not equal the parameters. The code I have, that is not working, is:
def suminout(nums,a,b):
total=0
for i in range(len(nums)):
if nums[i]!=a or nums[i]!=b:
total=total+nums[i]
return total
It appears to be summing everything in the list.
For example, if I called:
suminout([1,2,3,4],1,2)
it should return 7. However, I am getting 10.
Any thoughts?
As Kasramvd so duly noted, you need conjunction not disjunction.
Here is a list comprehension doing the same thing.
def suminout(nums, a, b):
total = 0
total = sum([x for x in nums if (x!=a and x!=b)])
return total
You need to use and instead of or.
def suminout(nums,a,b):
total=0
for i in range(len(nums)):
if nums[i]!=a and nums[i]!=b:
total=total+nums[i]
return total
Your for logic could be further simplified (without using len() and range()) as:
for num in nums:
if num not in [a, b]: # same as: num != a and num != b
total += num # same as: total = total + num
Better way to achieve it using list comprehension with sum() as mentioned by Sean. OR you may use filter() instead of list comprehension:
>>> my_list = [1, 2, 3, 4]
>>> sum(filter(lambda x: x !=1 and x!=4, my_list))
5
Or:
def suminout(nums, a, b):
total = 0
total = sum([x for x in nums if x not in (a,b)])
return total