Python3: Looping over a string - python

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'

Related

Checking if values from different lists are less than x

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)

Generated List consists of [Apparantly] unaccounted whitespaces in this code snippet

For a routine question on python programming, I was asked to generate a list of string sliced from one string (let's call it as target_string), with the length of each sliced string increasing from 1 to the length of string.
For example, if target_string is '123', I would have to generate the list like this : ['1', '2', '3', '12', '23', '123'].
For this, I wrote a code snippet that was something like this:
target_string = raw_input("Target String:")
length = len(target_string)
number_list = []
for i in range(length):
for j in range(length):
if j + i <= length:
number_list.append(target_string[j:j + i])
print(number_list)
On execution of this the result was:
Target String:12345
['', '', '', '', '', '1', '2', '3', '4', '5', '12', '23', '34', '45', '123', '234', '345', '1234', '2345']
The first thing I noticed is that the list consists of whitespaces as elements, and the number of whitespaces is equal to the length of the target_string. Why does this happen? Any kind of clarification and help is welcome.
P.S: I have a temperory workaround to generate the list that I need:
target_string = raw_input("Target String:")
length = len(target_string)
number_list = []
for i in range(length):
for j in range(length):
if j + i <= length:
number_list.append(target_string[j:j + i])
number_list.append(target_string)
del number_list[0:length]
target_list = [int(i) for i in number_list]
print(target_list)
Also feel free to suggest any changes or modifications to this, or any approach you would feel is more efficient and pythonic. Thanks in advance.
Edit: This is implemented in Pycharm, on Windows 10 , using Python 2.7, but please feel free to give the solutions in both the Python 2.7 and 3.X versions.
You can use itertools.combinations, then get the ones that the indexes are continuously adding 1, use ''.join(..) for converting it o a string and add it using .extend(..):
Python 2.7:
import itertools
target_string = raw_input("Target String:")
l=[]
for i in range(1,len(target_string)+1):
l.extend([''.join(i) for i in itertools.combinations(target_string,i) if all(int(y)-int(x)==1 for x, y in zip(i, i[1:]))])
print l
Output:
['1', '2', '3', '12', '23', '123']
Python 3.x:
import itertools
target_string = input("Target String:")
l=[]
for i in range(1,len(target_string)+1):
l.extend([''.join(i) for i in itertools.combinations(target_string,i) if all(int(y)-int(x)==1 for x, y in zip(i, i[1:]))])
print(l)
Output:
['1', '2', '3', '12', '23', '123']
Explaining why you got whitespaces in your code snippet.
Have a look at the loop part:
for i in range(length):
for j in range(length):
if j + i <= length:
number_list.append(target_string[j:j + i])
Here, both i and j gets initiated with 0.
So when we decode it, it comes like:
i = 0:
j=0:
0+0 < length
number_list.append(for i in range(length):
for j in range(length):
if j + i <= length:
number_list.append(target_string[0:0 + 0])) --> ['']
and so on.....

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)]

Best way of getting the longest sequence of even digits in an integer

What would be the most efficient way of getting the longest sequence of even digits in an integer in Python? For example, if I have a number 2456890048, the longest sequence should be 0048.
Should the integer be converted to a string to determine the longest sequence? Or should it be converted into the list and then, based on the indexes of each item, we would determine which sequence is the longest? Or is there a more efficient way that I am not aware of ( i am quite new to Python, and i am not sure what would be the best way to tackle this problem).
You can use itertools.groupby and max:
>>> from itertools import groupby
def solve(strs):
return max((list(g) for k, g in groupby(strs, key=lambda x:int(x)%2) if not k),
key=len)
...
>>> solve('2456890048') #or pass `str(2456890048)` if you've integers.
['0', '0', '4', '8']
>>> solve('245688888890048')
['6', '8', '8', '8', '8', '8', '8']
Here:
[list(g) for k, g in groupby('2456890048', key=lambda x:int(x)%2) if not k]
returns:
[['2', '4'], ['6', '8'], ['0', '0', '4', '8']]
Now we can apply max on this list(with key=len) to get the longest sequence. (Note that in the original code I am using a generator expression with max, so the list is not created in the memory.)
I think it is one of most efficient way
def longest(i):
curMax = m = 0
while i != 0:
d = i % 10 % 2
i = i / 10
if d == 0:
curMax += 1
else:
m = max(m, curMax)
curMax = 0
return max(m, curMax)
print longest(2456890048)
You can extract all runs of even numbers using a regexp, and find the longest using max.
import re
def longest_run(d):
return max(re.findall('[02468]+', str(d)), key=len)

Categories

Resources