Returned result is false with numpy conditions - python

I wrote a little script in order to return a list of 'characters' from a list of values :
List of values :
11
11
14
6
6
14
My script :
# -*- coding:utf-8 -*-
import numpy as np
data = np.loadtxt('/Users/valentinjungbluth/Desktop/produit.txt',
dtype = int)
taille = len(data)
for j in range (0, taille) :
if data[j] == 1 or 2 or 3 or 11 or 12 or 13 :
print 'cotisation'
if data[j] == 14 :
print 'donation'
else :
print 'part'
What I need to get :
'cotisation'
'cotisation'
'donation'
'part'
'part'
'donation'
What I get :
cotisation
part
cotisation
part
cotisation
donation
I don't see where I made an error ..
If someone could read my script and maybe correct him ?
Thank you

Try:
for j in range(0, taille):
if data[j] in {1, 2, 3, 11, 12, 13}:
print ("cotisation")
elif data[j] == 14:
print ("donation")
else:
print ("part")

There are a couple issues here:
if x == 1 or 2 or 3 or ... does not do what you are expecting.
Each clause is evaluated independently, so python does not know you are implying if x == 1 or x == 2 or x == 3, etc. It instead interprets this as if x == 1 or if 2 or if 3 ... if 2 and the like is actually a sensical if statement in python and is basically tantamount to asking if True (all non-zero integer values have a "truthiness" of True). So your statement is really equivalent to if data[j] == 1 or True or True or True or True, which reduces to if True. In other words, the condition is always satisfied regardless of the value. What you probably meant was:
if data[j] == 1 or data[j] == 2 or data[j] == 3 or data[j] == 11 ...
Your if-else construction has two blocks when one is intended
Currently boils down to something like the following in pseudocode:
if some condition:
print 'something'
now regardless of the first condition, if some other disjoint condition:
print 'something else'
otherwise:
print 'does not match other condition'
In other words, by using two ifs, the second if block, of which the else is a part, is treated as completely independent of the first if. So cases that satisfy the first condition could also satisfy the else, which is sounds like is not what you wanted as each character should print exactly once. If you want it to be 3 disjoint cases, you need to use elif instead so it is all considered part of a single block:
E.g.
if condition:
print 'something'
elif other condition:
print 'something else'
else:
print 'does not match EITHER of the two above condtions'

Scimonster point out your 1st issue in the code, you need elif for the second if.
The 2nd issue is the or part, your if condition is being intepret as
if (data[j] == 1) or 2 or 3 or 11 or 12 or 13
You could fixed them as below
if data[j] in [1, 2, 3, 11, 12, 13] :
print 'cotisation'
elif data[j] == 14 :
print 'donation'
else :
print 'part'

if data[j] == 1 or 2 or 3 or 11 or 12 or 13 :
print 'cotisation'
if data[j] == 14 :
print 'donation'
else :
print 'part'
You have two separate ifs here, and one has an else. They should all flow together, so the second should be elif.

Related

Formatting unknown output in a table in Python

Help! I'm a Python beginner given the assignment of displaying the Collatz Sequence from a user-inputted integer, and displaying the contents in columns and rows. As you may know, the results could be 10 numbers, 30, or 100. I'm supposed to use '\t'. I've tried many variations, but at best, only get a single column. e.g.
def sequence(number):
if number % 2 == 0:
return number // 2
else:
result = number * 3 + 1
return result
n = int(input('Enter any positive integer to see Collatz Sequence:\n'))
while sequence != 1:
n = sequence(int(n))
print('%s\t' % n)
if n == 1:
print('\nThank you! The number 1 is the end of the Collatz Sequence')
break
Which yields a single vertical column, rather than the results being displayed horizontally. Ideally, I'd like to display 10 results left to right, and then go to another line. Thanks for any ideas!
Something like this maybe:
def get_collatz(n):
return [n // 2, n * 3 + 1][n % 2]
while True:
user_input = input("Enter a positive integer: ")
try:
n = int(user_input)
assert n > 1
except (ValueError, AssertionError):
continue
else:
break
sequence = [n]
while True:
last_item = sequence[-1]
if last_item == 1:
break
sequence.append(get_collatz(last_item))
print(*sequence, sep="\t")
Output:
Enter a positive integer: 12
12 6 3 10 5 16 8 4 2 1
>>>
EDIT Trying to keep it similar to your code:
I would change your sequence function to something like this:
def get_collatz(n):
if n % 2 == 0:
return n // 2
return n * 3 + 1
I called it get_collatz because I think that is more descriptive than sequence, it's still not a great name though - if you wanted to be super explicit maybe get_collatz_at_n or something.
Notice, I took the else branch out entirely, since it's not required. If n % 2 == 0, then we return from the function, so either you return in the body of the if or you return one line below - no else necessary.
For the rest, maybe:
last_number = int(input("Enter a positive integer: "))
while last_number != 1:
print(last_number, end="\t")
last_number = get_collatz(last_number)
In Python, print has an optional keyword parameter named end, which by default is \n. It signifies which character should be printed at the very end of a print-statement. By simply changing it to \t, you can print all elements of the sequence on one line, separated by tabs (since each number in the sequence invokes a separate print-statement).
With this approach, however, you'll have to make sure to print the trailing 1 after the while loop has ended, since the loop will terminate as soon as last_number becomes 1, which means the loop won't have a chance to print it.
Another way of printing the sequence (with separating tabs), would be to store the sequence in a list, and then use str.join to create a string out of the list, where each element is separated by some string or character. Of course this requires that all elements in the list are strings to begin with - in this case I'm using map to convert the integers to strings:
result = "\t".join(map(str, [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]))
print(result)
Output:
12 6 3 10 5 16 8 4 2 1
>>>

Is there a way to increment the iterator if an 'if' condition is met

I'm solving this HackerRank challenge:
Alice has a binary string. She thinks a binary string is beautiful if and only if it doesn't contain the substring '010'.
In one step, Alice can change a 0 to a 1 or vice versa. Count and print the minimum number of steps needed to make Alice see the string as beautiful.
So basically count the number of '010' occurrences in the string 'b' passed to the function.
I want to increment i by 2 once the if statement is true so that I don't include overlapping '010' strings in my count.
And I do realize that I can just use the count method but I wanna know why my code isn't working the way I want to it to.
def beautifulBinaryString(b):
count = 0
for i in range(len(b)-2):
if b[i:i+3]=='010':
count+=1
i+=2
return count
Input: 0101010
Expected Output: 2
Output I get w/ this code: 3
You are counting overlapping sequences. For your input 0101010 you find 010 three times, but the middle 010 overlaps with the outer two 010 sequences:
0101010
--- ---
---
You can't increment i in a for loop, because the for loop construct sets i at the top. Giving i a different value inside the loop body doesn't change this.
Don't use a for loop; you could use a while loop:
def beautifulBinaryString(b):
count = 0
i = 0
while i < len(b) - 2:
if b[i:i+3]=='010':
count += 1
i += 2
i += 1
return count
A simpler solution is to just use b.count("010"), as you stated.
If you want to do it using a for loop, you can add a delta variable to keep track of the number of positions that you have to jump over the current i value.
def beautifulBinaryString(b):
count = 0
delta = 0
for i in range(len(b)-2):
try:
if b[i+delta:i+delta+3]=='010':
count+=1
delta=delta+2
except IndexError:
break
return count
You don't need to count the occurrences; as soon as you find one occurrence, the string is "ugly". If you never find one, it's beautiful.
def is_beautiful(b):
for i in range(len(b) - 2):
if b[i:i+3] == '010':
return False
return True
You can also avoid the slicing by simply keeping track of whether you've started to see 010:
seen_0 = False
seen_01 = False
for c in b:
if seen_01 and c == '0':
return False
elif seen_1 and c == '1':
seen_01 = True
elif c == '0':
seen_0 = True
else:
# c == 1, but it doesn't follow a 0
seen_0 = False
seen_01 = False
return True

Getting an IndexError: string index out of range

I'm not sure why I'm getting an
IndexError: string index out of range
with this code.
s = 'oobbobobo'
a = 0
for b in range(len(s)-1):
if (s[b] == 'b') and (s[b+1] == 'o') and (s[b+2] == s[b]):
a += 1
elif (s[b] == 'b') and (s[b+1] == 'o') and None:
break
print("Number of times bob occurs is: ", a)
I thought the elif statement would fix the error, so I'm lost.
In this case, the length of s is 9 which means that you're looping over range(8) and therefore the highest value that b will have is 7 (Stay with me, I'm going somewhere with this ...)
When b = 7 (on the last iteration of the loop), the conditional expression in the if statement is being checked which contains:
(s[b+2] == s[b])
Well, since b = 7, b + 2 = 9, but s[9] will be out of bounds (remember, python is 0 indexed so the highest index in a a string of length 9 is 8).
I'm guessing that the fix is to just modify the range statement:
for b in range(len(s)-2):
...

Validating the value of several variables

What I am after: The user is allowed to input only 0 or 1 (for a total of 4 variables). If the user inputs for example 2, 1, 1, 0 it should throw an error saying Only 0 and 1 allowed.
What I've tried so far:
if (firstBinary != 0 or firstBinary != 1 and secondBinary != 0
or secondBinary != 1 and thirdBinary != 0 or thirdBinary != 1
and forthBinary != 0 or forthBinary != 1):
print('Only 0 and 1 allowed')
else:
print('binary to base 10: result)
Problem: When I use such a statement, I get either the result even when I input for example 5, or I get 'only 0 and 1 allowed' even though I wrote all 1 or 0.
I found this which seemed to be what I was after, but it is still not working like I want it to:
if 0 in {firstBinary, secondBinary, thirdBinary, forthBinary} or 1 in \
{firstBinary, secondBinary, thirdBinary, forthBinary}:
print("Your result for binary to Base 10: ", allBinaries)
else:
print('Only 0 and 1 allowed')
This code basically gives me the same result as what I get with the first code sample.
Use any:
v1, v2, v3, v4 = 0, 1, 1, 2
if any(x not in [0, 1] for x in [v1, v2, v3, v4]):
print "bad"
of course, if you use a list it will look even better
inputs = [1, 1, 0 , 2]
if any(x not in [0, 1] for x in inputs):
print "bad"
This is due to the operator precedence in python. The or operator is of higher precedence than the and operator, the list looks like this:
or
and
not
!=, ==
(Source: https://docs.python.org/3/reference/expressions.html#operator-precedence)
So, python interprets your expression like this (the brackets are to clarify what is going on):
if (firstBinary != 0 or (firstBinary != 1 and secondBinary != 0 or (secondBinary != 1 and \
thirdBinary != 0 or (thirdBinary != 1 and forthBinary != 0 or (forthBinary != 1)))))
Which results in a different logic than what you want. There are 2 possible solutions to this, the first one is to add brackets to make the expression unambiguous. This is quite tedious and long-winded:
if ((firstBinary != 0 or firstBinary != 1) and (secondBinary != 0 or secondBinary != 1) and \
(thirdBinary != 0 or thirdBinary != 1) and (forthBinary != 0 or forthBinary != 1))
The other approach is to use the in-built all function:
vars = [firstBinary, secondBinary, thirdBinary, fourthBinary]
if not all(0 <= x <= 1 for x in vars):
print("Only 0 or 1 allowed")
I'd break it down into the two parts that you're trying to solve:
Is a particular piece of input valid?
Are all the pieces of input taken together valid?
>>> okay = [0,1,1,0]
>>> bad = [0,1,2,3]
>>> def validateBit(b):
... return b in (0, 1)
>>> def checkInput(vals):
... return all(validateBit(b) for b in vals)
...
>>> checkInput(okay)
True
>>> checkInput(bad)
False
>>>
values = [firstBinary, secondBinary, thirdBinary]
if set(values) - set([0, 1]):
print "Only 0 or 1, please"

Print a message instead of a number if certain conditions are met

I need to build a program that prints all the numbers between 1 to n, if we have a number that is divisible by 7 print "boom!" instead of a number, if the number has the digit 7, print "boom!" instead and if both print boom-boom!. For example, for n=18:
1
2
3
4
5
6
boom-boom!
8
9
10
11
12
13
boom!
15
16
boom!
18
This is what I did so far, I have almost no experience in coding so I must be doing something wrong here:
n=100
intlst=range(n+1)
strlst=str(range(n+1))
for i in intlst:
print(i)
if i % 7 == 0:
print("boom")
if "7" in strlst:
print("boop")
The modulo works but the string check doesn't. I tried to run it without the modulu part and I just get the normal 1 to 100 print.
If you're new to coding, a good idea is to write down your algorithm in a simple, "pseudocode" language. This way you won't get overwhelmed by weird names and functions. So if I understand correctly, you're looking for something like this:
for each *number* in the range [1,100] do:
if *number* is divisible by 7 and contains the number 7 then print "boom-boom!"
else if *number* has digit 7 in it or is divisible by 7, then print "boom!"
else print *number*
Now all you gotta do is translate this algorithm into python, and realli has beaten me to it ;)
Try this:
n = 100
for i in xrange(1, n + 1):
s = str(i)
if "7" in s and i % 7 == 0:
print "boom-boom!"
elif "7" in s or i % 7 == 0:
print "boom!"
else:
print i

Categories

Resources