Adding multiple elements in a list to list.count (Python) - list

Apologies for the somewhat vague title, I'll try explain more here.
Currently, I have the following code, which counts the number of times the values "y" and "n" show up in the list called "results".
NumberOfA = results.count("y")
NumberOfB = results.count("n")
Is there a way of making it so that, for example, values such as "yes" are also counted towards NumberOfA? I was thinking something along the lines of the following:
NumberOfA = results.count("y" and "yes" and "Yes")
NumberOfB = results.count("n" and "no" and "No")
But that doesn't work. This is probably a pretty easy one to solve, but hey. Thanks in advance!

As for why your answer above does not work, it is because Python will just take the final value of the expression you pass in:
>>> 'Yes' and 'y' and 'yes'
'yes'
Therefore your count will be off because it is just looking for that final value:
>>> results.count('yes' and 'y')
1
>>> results.count('yes' and '???')
0
Would something like this work? Note that this depends on their being only yes/no-esque answers in the list (will be wrong if things like 'Yeah....um no' are in there):
In [1]: results = ['yes', 'y', 'Yes', 'no', 'NO', 'n']
In [2]: yes = sum(1 for x in results if x.lower().startswith('y'))
In [3]: no = sum(1 for x in results if x.lower().startswith('n'))
In [4]: print yes, no
3 3
The general idea is to take your results list and then iterate through each item, lowercasing it and then taking the first letter (startswith) - if the letter is a y, we know it is a yes; otherwise, it will be no.
You can also combine the steps above if you want by doing something like this (note this requires Python 2.7):
>>> from collections import Counter
>>> results = ['yes', 'y', 'Yes', 'no', 'NO', 'n']
>>> Counter((x.lower()[0] for x in results))
Counter({'y': 3, 'n': 3})
Counter objects can be treated just like dictionaries, so you would now essentially have a dictionary that contained the counts of yes's and no's.

NumberOfA = results.count("y") + results.count("yes") + results.count("Yes")
NumberOfB = results.count("n") + results.count("no") + results.count("No")

Create a method
def multiCount(lstToCount, lstToLookFor):
total = 0
for toLookFor in lstToLookFor:
total = total + lstToCount.count(toLookFor)
return total
Then
NumberOfA = multiCount(results, ["y", "yes", "Yes"])
NumberOfB = multiCount(results, ["n", "no", "No"])

Related

For-loop error: list index out of range

So I am rather new to programming and just recently started with Classes and we are supposed to make a phonebook that can be loaded in seperate text files.
I however keep running into the problem in this section that when I get into the for-loop. It hits a brick wall on
if storage[2] == permaStorage[i].number:
And tells me "IndexError: list index out of range". I am almost certain it is due to permaStorage starts out empty, but even when I attempt to fill it with temporary instances of Phonebook it tells me it out of range. The main reason it is there is to check if a phone number already exists within the permaStorage.
Anyone got a good tip on how to solve this or work around it?
(Sorry if the text is badly written. Just joined this site and not sure on the style)
class Phonebook():
def __init__(self):
self.name = ''
self.number = ''
def Add(name1, number1):
y = Phonebook()
y.name = name1
y.number = number1
return y
def Main():
permaStorage = []
while True:
print " add name number\n lookup name\n alias name newname\n change name number\n save filename\n load filename\n quit\n"
choices = raw_input ("What would you like to do?: ")
storage = choices.split(" ")
if storage[0] == "add":
for i in range(0, len(permaStorage)+1):
if storage[2] == permaStorage[i].number:
print "This number already exists. No two people can have the same phonenumber!\n"
break
if i == len(permaStorage):
print "hej"
try:
tempbox = Add(storage[1], storage[2])
permaStorage.append(tempbox)
except:
raw_input ("Remember to write name and phonenumber! Press any key to continue \n")
I think problem is that permaStorage is empty list and then u try to:
for i in range(0, len(permaStorage)+1):
if storage[2] == permaStorage[i].number:
will cause an error because permaStorage has 0 items but u trying to get first (i=0, permaStorage[0]) item.
I think you should replace second if clause with first one:
for i in range(0, len(permaStorage)+1):
if i == len(permaStorage):
print "hej"
try:
tempbox = Add(storage[1], storage[2])
permaStorage.append(tempbox)
if storage[2] == permaStorage[i].number:
print "This number already exists. No two people can have the same phonenumber!\n"
break
So in this case if perStorage is blank you will append some value and next if clause will be ok.
Indexing starts at zero in python. Hence, a list of length 5 has the last element index as 4 starting from 0. Change range to range(0, len(permastorage))
You should iterate upto the last element of the list, not beyond.
Try -
for i in range(0, len(permaStorage)):
The list of numbers produced in range() is from the start, but not including the end, so range(3) == [0, 1, 2].
So if your list x has length 10, range(0, len(x)) will give you 0 through 9, which is the correct indices of the elements of your list.
Adding 1 to len(x) will produce the range 0 through 10, and when you try to access x[10], it will fail.

Appending a list built using conditional and appended values to a list of lists

I'm currently working with two large csv files of numerical data. One such csv, which we will call X, is composed entirely of numerical data for test subjects. The columns of a are arranged as health measurements like so (id, v1,v2,v3,v4). I am trying to take this information and create a list of lists where each list contains the information for a single person i.e as in this fashion:
X=[['1','a','b','c','d'],
['1','e','f','g','h'],
['2','i','j','k','l'],
['3','m','n','o','p']]
listoflists=[ [['1','a','b','c','d'],['1','e','f','g','h']], #first row
['2','i','j','k','l'], #second
['3','m','n','o','p'] ] #third
(let me know if i should edit the formatting: i wanted to present X as columns for readability. On list of lists I just ran out of room, so listolists = [ a,b,c], where a is the first row, b is the second, and c is third
I've tried something to the effect of this, but my biggest issue is I'm not sure where to create the list of those entities with matching data and then append it to the "master list".
#create a set that holds the values of the subject ids.
ids=list(set([item[0] for item in X]))
#create the list of lists i want
listolists=[]
for value in ids:
listolists.append(sublist)
for i in range(len(X))
sublist=[] #I'm not sure where to create sublists of
#matching data and append to listolists
if value == X[i][0]
sublist.append(X[i]
All help is appreciated. thanks.
Here is something:
X =[
['1','a','b','c','d'],
['1','e','f','g','h'],
['2','i','j','k','l'],
['3','m','n','o','p'],
]
numbers = {x[0] for x in X}
output = []
for num in sorted(numbers):
new_list = [sub_list for sub_list in X if sub_list[0] == num]
output.append(new_list)
print(output)
...
[[['1', 'a', 'b', 'c', 'd'], ['1', 'e', 'f', 'g', 'h']],
[['2', 'i', 'j', 'k', 'l']],
[['3', 'm', 'n', 'o', 'p']]]
If you need to 2nd and third list not nested like the first let me know
EDIT - for exact format specified in your question
X =[
['1','a','b','c','d'],
['1','e','f','g','h'],
['2','i','j','k','l'],
['3','m','n','o','p'],
]
numbers = {x[0] for x in X}
output = []
for num in sorted(numbers):
new_list = [sub_list for sub_list in X if sub_list[0] == num]
if len(new_list) > 1:
output.append(new_list)
else:
output.append((new_list)[0])
print(output)

Python - Assign None or value

Is there a short way to assign None or value in a variable, depending on the value?
x= value if value!= 999 else None
result = (on_false, on_true)[condition]
>>> value = 10
>>> x = (None,value)[value != 999]
>>> print x
10
>>> value = 999
>>> x = (None,value)[value != 999]
>>> print x
None
You are using the correct way to do it.
but if you insist on shorten way to figure it out you can use this method:
first way:
{0:value}.get(value==999)
using the trick python saving same hash for False and 0 (hash = 0).
second way:
{999:None}.get(value,value)
using get method and default value to bring this.
third way:
[None, value][value != 999]
when first part stand for value declaration and the second as boolean condition.

PYTHON 2.7 - Modifying List of Lists and Re-Assembling Without Mutating

I currently have a list of lists that looks like this:
My_List = [[This, Is, A, Sample, Text, Sentence] [This, too, is, a, sample, text] [finally, so, is, this, one]]
Now what I need to do is "tag" each of these words with one of 3, in this case arbitrary, tags such as "EE", "FF", or "GG" based on which list the word is in and then reassemble them into the same order they came in. My final code would need to look like:
GG_List = [This, Sentence]
FF_List = [Is, A, Text]
EE_List = [Sample]
My_List = [[(This, GG), (Is, FF), (A, FF), (Sample, "EE), (Text, FF), (Sentence, GG)] [*same with this sentence*] [*and this one*]]
I tried this by using for loops to turn each item into a dict but the dicts then got rearranged by their tags which sadly can't happen because of the nature of this thing... the experiment needs everything to stay in the same order because eventually I need to measure the proximity of tags relative to others but only in the same sentence (list).
I thought about doing this with NLTK (which I have little experience with) but it looks like that is much more sophisticated then what I need and the tags aren't easily customized by a novice like myself.
I think this could be done by iterating through each of these items, using an if statement as I have to determine what tag they should have, and then making a tuple out of the word and its associated tag so it doesn't shift around within its list.
I've devised this.. but I can't figure out how to rebuild my list-of-lists and keep them in order :(.
for i in My_List: #For each list in the list of lists
for h in i: #For each item in each list
if h in GG_List: # Check for the tag
MyDicts = {"GG":h for h in i} #Make Dict from tag + word
Thank you so much for your help!
Putting the tags in a dictionary would work:
My_List = [['This', 'Is', 'A', 'Sample', 'Text', 'Sentence'],
['This', 'too', 'is', 'a', 'sample', 'text'],
['finally', 'so', 'is', 'this', 'one']]
GG_List = ['This', 'Sentence']
FF_List = ['Is', 'A', 'Text']
EE_List = ['Sample']
zipped = zip((GG_List, FF_List, EE_List), ('GG', 'FF', 'EE'))
tags = {item: tag for tag_list, tag in zipped for item in tag_list}
res = [[(word, tags[word]) for word in entry if word in tags] for entry in My_List]
Now:
>>> res
[[('This', 'GG'),
('Is', 'FF'),
('A', 'FF'),
('Sample', 'EE'),
('Text', 'FF'),
('Sentence', 'GG')],
[('This', 'GG')],
[]]
Dictionary works by key-value pairs. Each key is assigned a value. To search the dictionary, you search the index by the key, e.g.
>>> d = {1:'a', 2:'b', 3:'c'}
>>> d[1]
'a'
In the above case, we always search the dictionary by its keys, i.e. the integers.
In the case that you want to assign the tag/label to each word, you are searching by the key word and finding the "value", i.e. the tag/label, so your dictionary would have to look something like this (assuming that the strings are words and numbers as tag/label):
>>> d = {'a':1, 'b':1, 'c':3}
>>> d['a']
1
>>> sent = 'a b c a b'.split()
>>> sent
['a', 'b', 'c', 'a', 'b']
>>> [d[word] for word in sent]
[1, 1, 3, 1, 1]
This way the order of the tags follows the order of the words when you use a list comprehension to iterate through the words and find the appropriate tags.
So the problem comes when you have the initial dictionary indexed with the wrong way, i.e. key -> labels, value -> words, e.g.:
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> [d[word] for word in sent]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'a'
Then you would have to reverse your dictionary, assuming that all elements in your value lists are unique, you can do this:
>>> from collections import ChainMap
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> d_inv = dict(ChainMap(*[{value:key for value in values} for key, values in d.items()]))
>>> d_inv
{'h': 2, 'c': 3, 'a': 1, 'x': 3, 'b': 2, 'd': 1}
But the caveat is that ChainMap is only available in Python3.5 (yet another reason to upgrade your Python ;P). For Python <3.5, solutions, see How do I merge a list of dicts into a single dict?.
So going back to the problem of assigning labels/tags to words, let's say we have these input:
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> sent = 'a b c a b'.split()
First, we invert the dictionary (assuming that there're one to one mapping for every word and its tag/label:
>>> d_inv = dict(ChainMap(*[{value:key for value in values} for key, values in d.items()]))
Then, we apply the tags to the words through a list comprehension:
>>> [d_inv[word] for word in sent]
[1, 2, 3, 1, 2]
And for multiple sentences:
>>> sentences = ['a b c'.split(), 'h a x'.split()]
>>> [[d_inv[word] for word in sent] for sent in sentences]
[[1, 2, 3], [2, 1, 3]]

Determining if an int exist in a list, without using the "in" function

I need to get user input to generate a list of 8 numbers, but when they input a number that is already in the list print and error . Without using the in function to determine if its in the list. Here's what I have so far.
def main():
myList = range(9)
a= True
for i in myList:
while a == True:
usrNum = int(input("Please enter a number: "))
if usrNum != myList[i]:
myList.append(usrNum)
print(i)
main()
Error for above code,
Scripts/untitled4.py", line 18, in main
myList.append(usrNum)
AttributeError: 'range' object has no attribute 'append'
The issue seems to be your way of generating myList. If you generate it with myList = [range(9)] you'll get:
[[0, 1, 2, 3, 4, 5, 6, 7, 8]]
Try using simply:
myList = range(9)
Also, you need to change myList.append[usrNum] with myList.append(usrNum) or you'll get a:
TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
You could also use wim's suggestion instead of the != operator:
if myList.__contains__(usrNum):
myList.append(usrNum)
There are two ways you can go about this:
Loop through the list to check each element.
The in operator is effectively doing:
for each value in the list:
if the value is what you're looking for
return True
if you reach the end of the list:
return False
If you can add that check into your code, you'll have your problem solved.
Use an alternate way of tracking which elements have been added
Options include a dict, or bits of an int.
For example, create checks = {}. When you add an value to the list, set checks[usrNum] = True. Then checks.get(usrNum, False) will return a boolean indicating whether the number already exists. You can simplify that with a collections.DefaultDict, but I suspect that may be more advanced than you're ready for.
The first is probably the result your instructor is after, so I'll give you a simple version to work with and massage to fit your needs.
myList = []
while True:
usrNum = int(input())
found = False
for v in myList:
if usrNum == v:
found = True
if not found:
myList.append(usrNum)
else:
#number was already in the list, panic!
Most instructors will be more impressed, and hence award better grades, if you can figure out how to do something like method 2, however.
You could do something like this, modify as needed (not sure when/if you want to break when the user enters a number that is already in the list, etc.)
This prompts for user input until they enter an item that already exists in the list, then it prints a message to the user, and stops execution.
def main():
mylist = range(9)
while True:
usrNum = int(input("Please enter a number: "))
if existsinlist(mylist, usrNum):
print("{} is already in the list {}".format(usrNum, mylist))
break
else:
mylist.append(usrNum)
def existsinlist(lst, itm):
for i in lst:
if itm == i:
return True
return False
Perhaps the point of this homework assignment is to help you understand how an operator like in is more efficient to read (and write, and compile) than the explicit loop that I used in the existsinlist function.
Not sure if list-comperehension would be allowable in this case, but you also could've done something like this, without relying on the existsinlist helper function:
def main():
mylist = range(9)
while True:
usrNum = int(input("Please enter a number: "))
if [i for i in mylist if i == usrNum]:
print("{} is already in the list {}".format(usrNum, mylist))
break
else:
mylist.append(usrNum)
In this case, the result of the list-comprehension can be evaluated for truthiness:
An empty list like [] results if no matching value exists, and this will be considered False
A non-empty list will result if at least one matching value exists, and this will be considered True
Yet another option which short-circuits and may be preferable:
if any(usrNum == i for i in mylist)