Checking if values from different lists are less than x - python

I can't use csv module so I'm opening a csv file like this:
def readdata(filename):
res = []
tmp = []
with open(filename) as f:
l = f.readlines()
for i in range(len(l)):
tmp.append(l[i].strip().split(';'))
for i in range(len(tmp)):
for j in range(len(tmp[i])):
if j > len(res)-1:
res.append([])
res[j].append(tmp[i][j])
return res
res_count_file = "count.csv"
data_count_file = readdata(res_count_file)
This csv file contain this:
ro1;ro2;ro3
5;3;5
8;2;4
6;2;666
15;6;3
2;1;
6;9;7
Now my function read this and splits them into a list of 3 lists :
[['ro1', '5', '8', '6', '15', '2', '6'], ['ro2', '3', '2', '2', '6', '1', '9'], ['ro3', '5', '4', '666', '3', '', '7']]
I need to check if the values of a row are each less then x(let's say x = 10), and if they're not then :score+= 1
For exemple:
5;3;5 //none of them are greater then x so score += 1
8;2;4 //none of them are greater then x so score += 1
15;6;3 // 15 is greater then x so nothing happens
2;1; // none of them are greater then x so score += 1 even if there is nothing in ro3, I need to convert the empty string "''" into 0
Now I've tried to call this function in a for loop to check if a number is less then X and to increment score if this returns true but I can't figure out how to check all 3 of the numbers in R01 R02 R03 as shown in the exemple.
def apprenant_fiable(data,index_of,i):
if data[index_of][i] == "":
return True
elif int(data[index_of][i]) <= 10 :
#print(data[index_of][i],"***PASS")
return True
else :
#print(data[index_of][i],"***FAIL")
return False
The goal is to output the total score.

You can use sum on a generator:
lst = [['ro1', '5', '8', '6', '15', '2', '6'], ['ro2', '3', '2', '2', '6', '1', '9'], ['ro3', '5', '4', '666', '3', '0', '7']]
val = 10
score = sum(all(y <= val for y in x) for x in zip(*[map(int, x[1:]) for x in lst]))
# 4
Note that I've replaced empty string in the list to '0', which you need to handle while forming the list.
val = 10
for x in zip(*[map(int, x[1:]) for x in lst]):
if all(y <= val for y in x):
print(x)
This will now print out all rows that contributed to adding score.

Your problem is in the head of your function:
def apprenant_fiable(data, index_of, i):
########
You specifically tell your function to look at only one of the three lists. Get rid of this. Inside the function you will somewhere have
for value, index in enumerate(data)
You will need to check all the values before deciding what to return.
If you can't figure out how to do this, there are many places to teach you how to look for presence of a certain quality in a collection.

you can do it easly using the pandas module
import pandas as pd
# read the csv
df = pd.read_csv('input.csv', delimiter=';').fillna(0)
# leave only the rows with sum greater then 10
print(df[df.sum(axis=1) > 10].shape[0])

Something like this? where list_of_3_lists is your result of reading the input file
total = 0
for l in list_of_3_lists:
if all([int(t) > 10 for t in l[1:]]):
total +=1
print(total)

Related

Python3: Looping over a string

I would like to program something in python 3 and do not understand where my mistake is.
seq = ('1gnadutnpawihv\n casc341')
check = ('0','1', '2', '3', '4', '5', '6', '7', '8', '9')
while i < len(seq):
for j in range(len(check)):
if seq[i] == check[j]:
seq=seq.replace(seq[i],"")
seq=seq.replace("\n","")
seq=seq.replace(" ","")
seq
I want to eliminate the characters "\n", " ", and all numbers from 0 to 9 from the string seq with the replace function. Now I want to iterate over the seq and compare each character with each character of the tuple check and detect the numbers 0 to 9 and replace them afterwards with nothing.
The replacement method works for "\n" and " ", but not for the numbers.
The output is simply:
'1gnadutnpawihvcasc341'
Why doesn't it work?
The problem was with the outer while loop. Instead of fixing it I removed it because it was redundant. I also removed the \n and spaces in the same loop:
seq = ('1gnadutnpawihv\n casc341')
check = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\n', ' ')
for j in range(len(check)):
seq = seq.replace(check[j], "")
print(seq)
Output:
gnadutnpawihvcasc
There are better ways to do what you're trying to do, but to answer your question
Why doesn't it work?
the answer becomes clear if you look at seq after the error:
In [1]: seq = ('1gnadutnpawihv\n casc341')
...:
...: check = ('0','1', '2', '3', '4', '5', '6', '7', '8', '9')
...:
...: i = 0
...: while i < len(seq):
...: for j in range(len(check)):
...: if seq[i] == check[j]:
...: seq=seq.replace(seq[i],"")
...:
...: i += 1
...:
...: seq=seq.replace("\n","")
...: seq=seq.replace(" ","")
...:
...: seq
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-1-ef8657e9ddaa> in <module>
6 while i < len(seq):
7 for j in range(len(check)):
----> 8 if seq[i] == check[j]:
9 seq=seq.replace(seq[i],"")
10
IndexError: string index out of range
In [2]: seq
Out[2]: 'gnadutnpawihv\n casc'
seq went from 24 characters down to 20. Generally, changing the thing you're iterating over causes things like this to happen in Python. I'm not actually sure how to get the output you posted, but I also had to make some changes (like define what i is) so I'm guessing your code has something else not shown.
There is no need for while or if statements. while is not necessary because for will terminate once it has iterated through the list given. if is not needed because replace() will have no affect if the passed substring is not present in the string. A for loop on its own is enough to produce he desired string.
Code:
seq = ('1gnadutnpawihv\n casc341')
for x in list(range(10))+[" ", "\n"]:
seq=seq.replace(f"{x}", "")
Output:
'gnadutnpawihvcasc'

How to produce a list of odd indices from a number in Python?

I want to produce a list containing only the odd indices of a Python integer number.
here is what I tried to do:
number = 5167460267890853
numberList = [num for num in str(number)]
oddIndex = [num for num in numberList if numberList.index(num) % 2 == 0]
print(oddIndex)
Output:
['5', '6', '4', '6', '0', '6', '8', '0', '8', '5']
Expected output:
['5', '6', '4', '0', '6', '8', '0', '5']
You can use string slicing with a step of 2.
Convert the number to a string, take only the odd indices and than convert to a list.
Using the this approach on your attempt, you could try:
number = 5167460267890853
numberList = [num for num in str(number)]
numberList = numberList[::2]
or just use the list built-in function:
number = 5167460267890853
oddIndex = list(str(number)[::2])
Both yield the desired output.
Answers to a similar question also use similar technique here
list.index() will return the index of the first seen element in the list. You can use enumerate() instead like this example:
number = 5167460267890853
out = [num for k, num in enumerate(str(number)) if not (k % 2)]
print(out)
# ['5', '6', '4', '0', '6', '8', '0', '5']

Finding the index of the first element of a list in another list

main_list = ['4', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
my_list = ['4', '5', '6']
My question is, how to find index of my_list in main_list?
The integers in my_list must be in consecutive order in main_list.
I tried using main_list.index(my_list[0]) but if there are more than one of a specific element, it returns the wrong index number. The result I need to get is 4, however with main_list.index(my_list[0]) it'll just give 0 as its index.
If there is any need for clarification, I can edit the post with additional details. Sorry, English is not my first language.
Try something like this
for i in range(len(main_list)-len(my_list)):
if main_list[i:i+len(my_list)] == my_list:
index = i
break
This should work for all possible types that could go in the lists.
You can convert both lists into a string using join() function and iteratively compare the strings to find a match.
EDIT: Made a change for it two work for multi-digit numbers. Added a float case as well.
For example:
main_list = ['4', '1', '2', '3', '40.1', '52', '61', '7', '8', '9', '10']
my_list = ['40.1', '52', '61']
index = -1
for i in range(len(main_list)):
if '#'.join(main_list[i:i+len(my_list)]) == '#'.join(my_list):
index = i
break
print(index)
If you would like an algorithm solution:
def Find(haystack, needle):
n, h = len(needle), len(haystack)
assert n <= h
for i in range(h):
if h - i <= n: break
count = 0
for i_, j in zip(range(i, i + n), range(n)):
if haystack[i_] == needle[j]:
count += 1
if count == n: return i
return -1
A much more effective one liner :
print ','.join(main_list).find(','.join(my_list)) - ''.join(main_list).find(''.join(my_list))
Converts them to strings with the elements separated by commas, finds the occurrence, then subtracts the occurrence found when the commas aren't there, and you have your answer.

Calculating averages

I've struggled with calculating average for values in 2 different lists. Here is what I have been doing (as newbie in python):
Averagelist = []
Listofvalues1 = ['1', '2', '3', '4']
Listofvalues2 = ['5', '6', '7', '8']
for i, x in enumerate(Listofvalues1):
for j, y in enumerate(Listofvalues2):
if j == i:
AVGvalue = (int(x)+int(y)/2)
Averagelist.append(AVGvalue)
I've come up with this way by myself. It might be useless, but so far I can print both values that I want to use for calculation but I get an error "ValueError: invalid literal for int() with base 10: 'somevalue'". Could it be the '' sign?
Cheers!
Do you need your data to be stored as strings? You will have to covert them to numbers (floats) at one time. This can be done without a for loop, using list comprehension:
Listofvalues1 = ['1', '2', '3', '4']
Listofvalues2 = ['5', '6', '7', '8']
Averagelist = [(float(v1)+float(v2))/2 for (v1, v2) in zip(Listofvalues1, Listofvalues2)]
To calculate the actual average without having it rounded down, use float. Also you needed an extra pair of brackets otherwise it would be y/2 rather than (x+y/2).
As for that error, I'm not sure what you're using in your Listofvalues lists as input, the the following worked fine for me.
Averagelist = []
Listofvalues1 = [1,2]
Listofvalues2 = [6,7]
for i, x in enumerate(Listofvalues1):
for j, y in enumerate(Listofvalues2):
if j == i:
AVGvalue = ((float(x)+float(y))/2)
Averagelist.append(AVGvalue)
print Averagelist
Did you mean (int(x)+int(y))/2 instead of (int(x)+int(y)/2)?
You can try:
averages = [(float(e[0]) + float(e[1]))/2 for e in zip(Listofvalues1, Listofvalues2)]

Python max with same number of instances

I have a list:
hello = ['1', '1', '2', '1', '2', '2', '7']
I wanted to display the most common element of the list, so I used:
m = max(set(hello), key=hello.count)
However, I realised that there could be two elements of the list that occur the same frequency, like the 1's and 2's in the list above. Max only outputs the first instance of a maximum frequency element.
What kind of command could check a list to see if two elements both have the maximum number of instances, and if so, output them both? I am at a loss here.
Using an approach similar to your current, you would first find the maximum count and then look for every item with that count:
>>> m = max(map(hello.count, hello))
>>> set(x for x in hello if hello.count(x) == m)
set(['1', '2'])
Alternatively, you can use the nice Counter class, which can be used to efficiently, well, count stuff:
>>> hello = ['1', '1', '2', '1', '2', '2', '7']
>>> from collections import Counter
>>> c = Counter(hello)
>>> c
Counter({'1': 3, '2': 3, '7': 1})
>>> common = c.most_common()
>>> common
[('1', 3), ('2', 3), ('7', 1)]
Then you can use a list comprehension to get all the items that have the maximum count:
>>> set(x for x, count in common if count == common[0][1])
set(['1', '2'])
Edit: Changed solution
>>> from collections import Counter
>>> from itertools import groupby
>>> hello = ['1', '1', '2', '1', '2', '2', '7']
>>> max_count, max_nums = next(groupby(Counter(hello).most_common(),
lambda x: x[1]))
>>> print [num for num, count in max_nums]
['1', '2']
from collections import Counter
def myFunction(myDict):
myMax = 0 # Keep track of the max frequence
myResult = [] # A list for return
for key in myDict:
print('The key is', key, ', The count is', myDict[key])
print('My max is:', myMax)
# Finding out the max frequence
if myDict[key] >= myMax:
if myDict[key] == myMax:
myMax = myDict[key]
myResult.append(key)
# Case when it is greater than, we will delete and append
else:
myMax = myDict[key]
del myResult[:]
myResult.append(key)
return myResult
foo = ['1', '1', '5', '2', '1', '6', '7', '10', '2', '2']
myCount = Counter(foo)
print(myCount)
print(myFunction(myCount))
Output:
The list: ['1', '1', '5', '2', '1', '6', '7', '10', '2', '2']
Counter({'1': 3, '2': 3, '10': 1, '5': 1, '7': 1, '6': 1})
The key is 10 , The count is 1
My max is: 0
The key is 1 , The count is 3
My max is: 1
The key is 2 , The count is 3
My max is: 3
The key is 5 , The count is 1
My max is: 3
The key is 7 , The count is 1
My max is: 3
The key is 6 , The count is 1
My max is: 3
['1', '2']
I wrote this simple program, I think it might also work. I was not aware of the most_common() function until I do a search. I think this will return as many most frequent element there is, it works by comparing the max frequent element, when I see a more frequent element, it will delete the result list, and append it once; or if it is the same frequency, it simply append to it. And keep going until the whole Counter is iterated through.

Categories

Resources