python counter with target value - python

I am trying to take,as arguments, two values: a list and a target value. It returns the # number of times that the target value appears in the list.
def countTarget(myList, target):
#initialize the counter to zero
counter = 0
for element in myList:
#compare the value in the list to the target value
#if they are the same, increment the counter
if element == target:
counter = counter + 1
return counter

Okay there are going to be better answers, but here's one.
def countTarget(myList, target):
return sum([x == target for x in myList])
Edit
There's a much better alternative in the comments.
myList.count(target)
...

Use the Counter class. It's a special type of dict that works very well for counting the frequency of a particular value inside a list (as opposed to using a dict yourself) because it will circumvent some nits like running into a KeyError when trying to count a target that doesn't exist in the list (Counter on the other hand will just return 0).
from collections import Counter
def countTarget(myList, target):
return Counter(myList)[target]
Alternatively, you can use the bult in count function for lists, as mentioned in a comment below your question.
def countTarget(myList, target): return myList.count(target)
However, at that point your countTarget function isn't doing you much good. If you really want to have both objects be parameters, you can also use the count function from a static context...
list.count(myList, target)
But seriously, just use myList.count(target). It's probably the most simple and straightforward for your use case (by the looks of it). If you need to count targets multiple times, then consider keeping your own Counter as mentioned before.

Related

How to find the most common string(s) in a Python list?

I am dealing with ancient DNA data. I have an array with n different base pair calls for a given coordinate.
e.g.,
['A','A','C','C','G']
I need to setup a bit in my script whereby the most frequent call(s) are identified. If there is one, it should use that one. If there are two (or three) that are tied (e.g., A and C here), I need it randomly pick one of the two.
I have been looking for a solution but cannot find anything satisfactory. The most frequent solution, I see is Counter, but Counter is useless for me as c.most_common(1) will not identify that 1 and 2 are tied.
You can get the maximum count from the mapping returned by Counter with the max function first, and then ues a list comprehension to output only the keys whose counts equal the maximum count. Since Counter, max, and list comprehension all cost linear time, the overall time complexity of the code can be kept at O(n):
from collections import Counter
import random
lst = ['A','A','C','C','G']
counts = Counter(lst)
greatest = max(counts.values())
print(random.choice([item for item, count in counts.items() if count == greatest]))
This outputs either A or C.
Something like this would work:
import random
string = ['A','A','C','C','G']
dct = {}
for x in set(string):
dct[x] = string.count(x)
max_value = max(dct.values())
lst = []
for key, value in dct.items():
if value == max_value:
lst.append(key)
print(random.choice(lst))

How to change this code to recursive code

Here's my python code
def search(myList, number):
for i in myList:
if i[0] == number:
return i[1]
return None
myList = [(5107261, 'Ernst'), (6524256, 'Arvo')]
number = 5107261
print(search(myList, number))
Now I want to write it using recursion but I'm not sure how to do it. I need some pointers to help me get started.
When writing recursive code, you want to define a base case, and you want to define a method for making your problem smaller on every step. In this example, we are working with lists, so a good base case would be an empty list, []. If the list is empty, it makes sense to return None. In your recursive case, you want to do some work to make the problem smaller. In this case we can check one element, and if that element is not what we are searching for, we can call the function again on a smaller version of the list.
Our result is a function like this:
def searchR(myList, number):
if length(myList) == 0: return None
elif myList[0][0] == number: return myList[0][1]
else: return searchR(myList[1:], number)
There are 3 cases. Case 1 is our base case, where the length of the list is 0. Case 2 is our success case, where we found the the target of the search. Case 3 is where we make our recursive call. Notice how the first element is removed from the new list! If the first element isn't removed, the function will loop forever.

How to return a list that is made up of extracted elements from another list in python?

I am building a function to extract all negatives from a list called xs and I need it to add those extracted numbers into another list called new_home. I have come up with a code that I believe should work, however; it is only showing an empty list.
Example input/output:
xs=[1,2,3,4,0,-1,-2,-3,-4] ---> new_home=[1,2,3,4,0]
Here is my code that returns an empty list:
def extract_negatives(xs):
new_home=[]
for num in range(len(xs)):
if num <0:
new_home= new_home+ xs.pop(num)
return
return new_home
Why not use
[v for v in xs if v >= 0]
def extract_negatives(xs):
new_home=[]
for num in range(len(xs)):
if xs[num] < 0:
new_home.append(xs[num])
return new_home
for your code
But the Chuancong Gao solution is better:
def extract_negative(xs):
return [v for v in xs if v >= 0]
helper function filter could also help. Your function actually is
new_home = filter(lambda x: x>=0, xs)
Inside the loop of your code, the num variable doesn't really store the value of the list as you expect. The loop just iterates for len(xs) times and passes the current iteration number to num variable.
To access the list elements using loop, you should construct loop in a different fashion like this:
for element in list_name:
print element #prints all element.
To achieve your goal, you should do something like this:
another_list=[]
for element in list_name:
if(element<0): #only works for elements less than zero
another_list.append(element) #appends all negative element to another_list
Fortunately (or unfortunately, depending on how you look at it) you aren't examining the numbers in the list (xs[num]), you are examining the indexes (num). This in turn is because as a Python beginner you probably nobody haven't yet learned that there are typically easier ways to iterate over lists in Python.
This is a good (or bad, depending on how you look at it) thing, because had your code taken that branch you would have seen an exception occurring when you attempted to add a number to a list - though I agree the way you attempt it seems natural in English. Lists have an append method to put new elements o the end, and + is reserved for adding two lists together.
Fortunately ignorance is curable. I've recast your code a bit to show you how you might have written it:
def extract_negatives(xs):
out_list = []
for elmt in xs:
if elmt < 0:
out_list.append(elmt)
return out_list
As #ChuangongGoa suggests with his rather terse but correct answer, a list comprehension such as he uses is a much better way to perform simple operations of this type.

How to limit the depth of recursion in python?

I have a list of elements. I want to know if there are two pairs of elements in the list, in which the elements of the pair have the same value.
My idea is that I first compare all the elements in the list, if a pair is found, remove the pair from the list, then proceed again. Thus I think I can use recursion to do this task, but limit the depth to 2 to solve the problem.
Here is my first try:
recursion_depth=0
def is_twopair(card):
nonlocal recursion_depth
if recursion_depth==2: return True
for i in range(0, len(card)):
for k in range(i+1,len(card)):
if card[i].value==card[k].value:
del card[k], card[i]
recursion_depth+=1
is_twopair(card)
else: continue
else: continue
else: return False
I use the variable recursion_depth to record the the depth of recursion, but then realize that the return command doesn't immediately terminate the function and return true, but returns to its original caller is_twopair(card) instead. So my question is:
Is there a way to immediately terminate the function and return the result true?
Is there a way to limit the depth of recursion?
I know there maybe several ways to work around this. But I want to stay faithful to my idea and use this as an opportunity for learning.
I don't believe you can "break out" of the recursion without some serious black magic, nor do I believe that you should try to. Cascading the return value up the calling chain is typically a fine approach.
I'd personally avoid using a nonlocal variable and keep track of the recursion depth within the scope of each function call.
def remove_pairs(card, count=2, depth=0):
if depth == count:
return card
for i in range(0, len(card)):
for j in range(i+1, len(card)):
if card[i].value == card[j].value:
del card[j], card[i]
return remove_pairs(card, count, depth+1) # add return here
Moving the tracking of the depth into the function itself will allow the function to be called repeatedly from different locations without issue.
Additionally, the code can be cleaned up some using itertools.combinations.
from itertools import combinations
def remove_pairs(cards, count=2, depth=0):
if depth == count:
return cards
for card1, card2 in combinations(cards, 2):
if card1.value == card2.value:
cards.remove(card1)
cards.remove(card2)
return remove_pairs(cards, count, depth+1)
I think the piece you're missing is a return call to pass on the results of a recursive call back up to the previous caller:
if card[i].value==card[k].value:
del card[k], card[i]
recursion_depth+=1
return is_twopair(card) # add return here!
I don't really think recursion is a natural way to solve this problem, but with the above change, it should work. You could avoid needing to use a nonlocal variable by passing the depth as an optional parameter.
yourList = [1,1,2,2,3,4]
yourDict = {}
for i in yourList:
yourDict[i] = yourList.count(i)
This code will return the number of ocurrences for every value in the list so you can determinate the number of pairs..
In this case:
yourDict - - > {1: 2, 2: 2, 3: 1, 4: 1}
The value 1 appear 2 times, the value 2 appear 2 times, the value 3 and 4 appear 1 time.

for-in loop's upper limit changing in each loop

How can I update the upper limit of a loop in each iteration? In the following code, List is shortened in each loop. However, the lenList in the for, in loop is not, even though I defined lenList as global. Any ideas how to solve this? (I'm using Python 2.sthg)
Thanks!
def similarity(List):
import difflib
lenList = len(List)
for i in range(1,lenList):
import numpy as np
global lenList
a = List[i]
idx = [difflib.SequenceMatcher(None, a, x).ratio() for x in List]
z = idx > .9
del List[z]
lenList = len(List)
X = ['jim','jimmy','luke','john','jake','matt','steve','tj','pat','chad','don']
similarity(X)
Looping over indices is bad practice in python. You may be able to accomplish what you want like this though (edited for comments):
def similarity(alist):
position = 0
while position < len(alist):
item = alist[position]
position += 1
# code here that modifies alist
A list will evaluate True if it has any entries, or False when it is empty. In this way you can consume a list that may grow during the manipulation of its items.
Additionally, if you absolutely have to have indices, you can get those as well:
for idx, item in enumerate(alist):
# code here, where items are actual list entries, and
# idx is the 0-based index of the item in the list.
In ... 3.x (I believe) you can even pass an optional parameter to enumerate to control the starting value of idx.
The issue here is that range() is only evaluated once at the start of the loop and produces a range generator (or list in 2.x) at that time. You can't then change the range. Not to mention that numbers and immutable, so you are assigning a new value to lenList, but that wouldn't affect any uses of it.
The best solution is to change the way your algorithm works not to rely on this behaviour.
The range is an object which is constructed before the first iteration of your loop, so you are iterating over the values in that object. You would instead need to use a while loop, although as Lattyware and g.d.d.c point out, it would not be very Pythonic.
What you are effectively looping on in the above code is a list which got generated in the first iteration itself.
You could have as well written the above as
li = range(1,lenList)
for i in li:
... your code ...
Changing lenList after li has been created has no effect on li
This problem will become quite a lot easier with one small modification to how your function works: instead of removing similar items from the existing list, create and return a new one with those items omitted.
For the specific case of just removing similarities to the first item, this simplifies down quite a bit, and removes the need to involve Numpy's fancy indexing (which you weren't actually using anyway, because of a missing call to np.array):
import difflib
def similarity(lst):
a = lst[0]
return [a] + \
[x for x in lst[1:] if difflib.SequenceMatcher(None, a, x).ratio() > .9]
From this basis, repeating it for every item in the list can be done recursively - you need to pass the list comprehension at the end back into similarity, and deal with receiving an empty list:
def similarity(lst):
if not lst:
return []
a = lst[0]
return [a] + similarity(
[x for x in lst[1:] if difflib.SequenceMatcher(None, a, x).ratio() > .9])
Also note that importing inside a function, and naming a variable list (shadowing the built-in list) are both practices worth avoiding, since they can make your code harder to follow.

Categories