reading second float in a line in python [duplicate] - python

This question already has answers here:
split string by arbitrary number of white spaces
(6 answers)
Closed 6 years ago.
I wrote a simple program to read some floats from a file:
line2 = f1.readline()
if "Totals" in line2:
cline = line2.strip()
csline= cline.split(" ")
zforcet = float(csline[7])
torquet = float(csline[8])
line2 in question is :
Totals 7.911647E+03 -1.191758E+03 7.532665E+03 4.137034E+00
My code works, but my question is this there a more obvious way to code this ?
I mean it is not at all obvious to me that the second real number on the line is csline[7] and i could do this only after trail and error and printing out the contents of csline. I am looking for a way to "read the second float" on a line directly.

Just use split() It will split on every whitespace and you ll get a list like this:
["Totals", "7.911647E+03", "-1.191758E+03", "7.532665E+03", "4.137034E+00"]
So the first element of the list will be "7.911647E+03"
Also note, that it will be a string by default, you ll have to make it a float, using the float function. (eg float("7.911647E+03"))
EDIT: As highlighted in the comment if you are really looking for a way to "read the second float" on a line directly Than i would iterate over the splitted line, and check the types of the elements, and grab the second float type.
splitted_line = ["Totals", "7.911647E+03", "-1.191758E+03", "7.532665E+03", "4.137034E+00"]
counter = 1
for i in splitted_line:
try:
float(i)
counter += 1
if counter== 2:
print(i)
except ValueError:
pass
This will print out 7.911647E+03

I would go for automated trial and error in case we can not be sure that the second number in a line (which you want) is always the third word (space-separated characters/digits):
line2 = f1.readline()
if "Totals" in line2:
numbers = []
for word in line2.split():
try:
number.append(float(word))
except ValueError:
pass
zforcet = numbers[2] if len(numbers) > 2 else 0
torquet = numbers[3] if len(numbers) > 3 else 0
We split the line into words and try to convert each word to a float number. If it succeeds, we append the number to our list, if not we don't care.
Then after having parsed the line, we can simply pick the n-th number from out numbers list - or a default value (0) if we could not parse enough numbers.

You want to:
Make a list with all the float values out of line2
Do something with the second element of that list
For that you'll have to:
Make a helper function to check if something is a float
Split line2 and pass each element to your helper function
Keep only the actual floats
Once you have a list of actual floats in line2, it's just a matter of knowing which item you want to pick (in this case, the second one, so floats[1].
--
def is_float(e):
try:
float(e)
except ValueError:
return False
return True
def get_floats(line):
return [float(item) for item in line.rstrip().split() if is_float(item)]
After which your code becomes:
line2 = f1.readline()
if "Totals" in line2:
floats = get_floats(line2)
zforcet = floats[1] # -1191.758
torquet = floats[2] # 7532.665
Which is not so much shorter but somewhat clearer and easier to debug.
If you plan to reuse the above code, you could also abstract the indexes of items you want to pick:
ZFORCET = 1
TORQUET = 2
And then:
line2 = f1.readline()
if "Totals" in line2:
floats = get_floats(line2)
zforcet = floats[ZFORCET]
torquet = floats[TORQUET]

Related

Longest sequence of equal numbers in python

I tried to generate the longest sequence of equal numbers in python, but it doesn't work
def lista_egale(lst1 = input("numbers go here ")):
l = 0
lst1 = []
maxi = -9999
prev_one = None
lmax = -9999
for current in lst1:
if prev_one == current:
l += 1
else:
l = 1
if l > lmax:
lmax = l
maxi = current
prev_one = current
print("longest sequence is ", lmax, " and ", maxi)
lista_egale()
Input:
1 2 2 2 2 3 4 5 6 2 2 2
Expected Output:
longest sequence is 4 and 2
I was going to write up the same concern about your default argument, but that would at least work correctly the first time it is called. This function does not. Everyone jumped on that common problem, and failed to notice the next line. Let's look another look at this abridged version of your code:
irrelevant = input("numbers go here ")
def lista_egale(lst1 = irrelevant):
# while it is true that your default argument is bad,
# that doesn't matter because of this next line:
lst1 = []
for current in lst1:
# unreachable code
pass
To clarify, since your reply indicates this is not clear enough, it doesn't matter what value was passed in to lst1 if you immediately overwrite it with an empty list.
(for others reading this:) Separating out what I labeled "irrelevant" is not quite identical, but I'm trying to point out that the input was overwritten.
I don't think this function should take user input or have a default argument at all. Let it be a function with one job, and just pass it the data to work on. User input can be collected elsewhere.
Based on Barmar's note, and the principle of using only unmutable default values, your code should look something more like this:
def lista_egale(inp1 = None):
if not inp1:
inp1 = input("numbers go here ")
# optionally do some error checking for nonnumerical characters here
lst1 = [int(i) for i in inp1.split(" ")]
# rest of your code here
lista_egale()
Basically, input returns a string value, and you need to convert it into a list of integers first before you start working on it.
You can swap out the list comprehension for map(int, inp1.split(" ")) as it will do the same (but you can't iterate through a map more than once unless you wrap it in a list() function first).
Secondly, avoid setting mutable default arguments as (in short) can lead to weird results when rerunning the same function multiple times.

How to delete randomly inserted characters at specific locations in a string?

I was previously working on a problem of String encryption: How to add randomly generated characters in specific locations in a string? (obfuscation to be more specific).
Now I am working on its second part that is to remove the randomly added characters and digits from the obfuscated String.
My code works for removing one random character and digit from the string (when encryption_str is set to 1) but for removing two, three .. nth .. number of characters (when encryption_str is set to 2, 3 or n), I don't understand how to modify it.
My Code:
import string, random
def decrypt():
encryption_str = 2 #Doesn't produce correct output when set to any other number except 1
data = "osqlTqlmAe23h"
content = data[::-1]
print("Modified String: ",content)
result = []
result[:0] = content
indices = []
for i in range(0, encryption_str+3): #I don't understand how to change it
indices.append(i)
for i in indices:
del result[i+1]
message = "".join(result)
print("Original String: " ,message)
decrypt()
Output for Encryption level 1 (Correct Output)
Output for Encryption level 2 (Incorrect Output)
That's easy to append chars, that's a bit more difficult to remove them, because that changes the string length and the position of the chars.
But there is an easy way : retrieve the good ones, and for that you just need to iterate with the encryption_str+1 as step (that avoid adding an if on the indice)
def decrypt(content, nb_random_chars):
content = content[::-1]
result = []
for i in range(0, len(content), nb_random_chars + 1):
result.append(content[i])
message = "".join(result)
print("Modified String: ", content)
print("Original String: ", message)
# 3 lines in 1 with :
result = [content[i] for i in range(0, len(content), nb_random_chars + 1)]
Both will give hello
decrypt("osqlTqlmAe23h", 2)
decrypt("osqFlTFqlmFAe2F3h", 3)
Why not try some modulo arithmetic? Maybe with your original string, you try something like:
''.join([x for num, x in enumerate(data) if num % encryption_str == 0])
How about a list comprehension (which is really just a slightly more compact notation for #azro's answer)?
result = content[0::(encryption_str+1)]
That is, take every encryption_str+1'd character from content starting with the first.

Intro to Python - Lists questions

we've started doing Lists in our class and I'm a bit confused thus coming here since previous questions/answers have helped me in the past.
The first question was to sum up all negative numbers in a list, I think I got it right but just want to double check.
import random
def sumNegative(lst):
sum = 0
for e in lst:
if e < 0:
sum = sum + e
return sum
lst = []
for i in range(100):
lst.append(random.randrange(-1000, 1000))
print(sumNegative(lst))
For the 2nd question, I'm a bit stuck on how to write it. The question was:
Count how many words occur in a list up to and including the first occurrence of the word “sap”. I'm assuming it's a random list but wasn't given much info so just going off that.
I know the ending would be similar but no idea how the initial part would be since it's string opposed to numbers.
I wrote a code for a in-class problem which was to count how many odd numbers are on a list(It was random list here, so assuming it's random for that question as well) and got:
import random
def countOdd(lst):
odd = 0
for e in lst:
if e % 2 = 0:
odd = odd + 1
return odd
lst = []
for i in range(100):
lst.append(random.randint(0, 1000))
print(countOdd(lst))
How exactly would I change this to fit the criteria for the 2nd question? I'm just confused on that part. Thanks.
The code to sum -ve numbers looks fine! I might suggest testing it on a list that you can manually check, such as:
print(sumNegative([1, -1, -2]))
The same logic would apply to your random list.
A note about your countOdd function, it appears that you are missing an = (== checks for equality, = is for assignment) and the code seems to count even numbers, not odd. The code should be:
def countOdd(lst):
odd = 0
for e in lst:
if e%2 == 1: # Odd%2 == 1
odd = odd + 1
return odd
As for your second question, you can use a very similar function:
def countWordsBeforeSap(inputList):
numWords = 0
for word in inputList:
if word.lower() != "sap":
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList))
To explain the above, the countWordsBeforeSap function:
Starts iterating through the words.
If the word is anything other than "sap" it increments the counter and continues
If the word IS "sap" then it returns early from the function
The function could be more general by passing in the word that you wanted to check for:
def countWordsBefore(inputList, wordToCheckFor):
numWords = 0
for word in inputList:
if word.lower() != wordToCheckFor:
numWords = numWords + 1
else:
return numWords
inputList = ["trees", "produce", "sap"]
print(countWordsBeforeSap(inputList, "sap"))
If the words that you are checking come from a single string then you would initially need to split the string into individual words like so:
inputString = "Trees produce sap"
inputList = inputString.split(" ")
Which splits the initial string into words that are separated by spaces.
Hope this helps!
Tom
def count_words(lst, end="sap"):
"""Note that I added an extra input parameter.
This input parameter has a default value of "sap" which is the actual question.
However you can change this input parameter to any other word if you want to by
just doing "count_words(lst, "another_word".
"""
words = []
# First we need to loop through each item in the list.
for item in lst:
# We append the item to our "words" list first thing in this loop,
# as this will make sure we will count up to and INCLUDING.
words.append(item)
# Now check if we have reached the 'end' word.
if item == end:
# Break out of the loop prematurely, as we have reached the end.
break
# Our 'words' list now has all the words up to and including the 'end' variable.
# 'len' will return how many items there are in the list.
return len(words)
lst = ["something", "another", "woo", "sap", "this_wont_be_counted"]
print(count_words(lst))
Hope this helps you understand lists better!
You can make effective use of list/generator comprehensions. Below are fast and memory efficient.
1. Sum of negatives:
print(sum( i<0 for i in lst))
2. Count of words before sap: Like you sample list, it assumes no numbers are there in list.
print(lst.index('sap'))
If it's a random list. Filter strings. Find Index for sap
l = ['a','b',1,2,'sap',3,'d']
l = filter(lambda x: type(x)==str, l)
print(l.index('sap'))
3. Count of odd numbers:
print(sum(i%2 != 0 for i in lst))

sorting lines of file python

I want to Bubblesort a file by numbers and I have propably 2 mistakes in my code.
The lines of the file contain: string-space-number
The response is a wrong sorting or sometimes I got also an IndexError because x.append(row[l]) is out of range
Hope someone can help me
Code:
#!/usr/bin/python
filename = "Numberfile.txt"
fo = open(filename, "r")
x, y, z, b = [], [], [], []
for line in fo: # read
row = line.split(" ") # split items by space
x.append(row[1]) # number
liste = fo.readlines()
lines = len(liste)
fo.close()
for passesLeft in range(lines-1, 0, -1):
for i in range(passesLeft):
if x[i] > x[i+1]:
temp = liste[i]
liste[i] = liste[i+1]
liste[i+1] = temp
fo = open(filename, "w")
for i in liste:
fo.writelines("%s" % i)
fo.close()
Seems that you have empty lines in the file.
Change:
for line in fo: # read
row = line.split(" ") # split items by space
x.append(row[1]) # number
with:
for line in fo: # read
if line.strip():
row = line.split(" ") # split items by space
x.append(row[1]) # number
By the way, you're better off using re.split with the regex \s+:
re.split(r'\s+', line)
which will make your code more resilient - it will be able to handle multiple spaces as well.
For the second issue Anand proceeded me: you're comparing strings, if you want to compare numbers you'll have to wrap it with a call to int()
First issue, if you are sorting based on the numbers and the numbers can be multiple digits, then your logic would not work because x is a list of strings , not integers, and when comparing strings, it compares lexicographically, that is '12' is less than 2 , etc. You should convert the number to int before appending to x list.
Also if you are getting ListIndex error, you may have empty lines or lines without 2 elements, you should correctly check you input, also you can add a condition to ignore the empty lines.
Code -
for line in fo:
if line.strip():
row = line.split(" ")
x.append(int(row[1]))

Python number to word converter needs a space detector

I have been working on a sort of encryption tool in python. This bit of code is for the decryption feature.
The point is to take the given numbers and insert them into a list from where they will be divided by the given keys.
My idea for code is below but I keep getting the out of list index range whenever I try it out. Any suggestions? Keep in mind I'm a beginner:
need = []
detr = raw_input('What would you like decrypted?')
count = 0
for d in detr:
if (d == '.' or d == '!') or (d.isalpha() or d== " "):
count +=1
else:
need[count].append(d)
The problem is you are attempting to overwrite list values that don't exist.
list.append(item) adds item to the end of list. list[index] = item inserts item into list at position index.
list = [0,0,0]
list.append(0) # = [0,0,0,0]
list[0] = 1 # [1,0,0,0]
list[99] = 1 # ERROR: out of list index range
You should get rid of the count variable entirely. You could append None in the case of d==' ' etc. or just ignore them.
The way I understood your description you want to extract the numbers in a string and append them to a list using a for-loop to iterate over each character.
I think it would be easier doing it with regular expressions (something like r'([\d]+)').
But the way joconner said: "get rid of the count variable":
need = []
detr = input('What would you like decrypted?\n')
i = iter(detr) # get an iterator
# iterate over the input-string
for d in i:
numberstr = ""
try:
# as long as there are digits
while d.isdigit():
# append them to a cache-string
numberstr+= d
d = next(i)
except StopIteration:
# occurs when there are no more characters in detr
pass
if numberstr != "":
# convert the cache-string to an int
# and append the int to the need-array
need.append( int(numberstr) )
# print the need-array to see what is inside
print(need)

Categories