I'm trying to make a function that will compare multiple variables to an integer and output a string of three letters. I was wondering if there was a way to translate this into Python. So say:
x = 0
y = 1
z = 3
mylist = []
if x or y or z == 0:
mylist.append("c")
if x or y or z == 1:
mylist.append("d")
if x or y or z == 2:
mylist.append("e")
if x or y or z == 3:
mylist.append("f")
which would return a list of:
["c", "d", "f"]
You misunderstand how boolean expressions work; they don't work like an English sentence and guess that you are talking about the same comparison for all names here. You are looking for:
if x == 1 or y == 1 or z == 1:
x and y are otherwise evaluated on their own (False if 0, True otherwise).
You can shorten that using a containment test against a tuple:
if 1 in (x, y, z):
or better still:
if 1 in {x, y, z}:
using a set to take advantage of the constant-cost membership test (i.e. in takes a fixed amount of time whatever the left-hand operand is).
Explanation
When you use or, python sees each side of the operator as separate expressions. The expression x or y == 1 is treated as first a boolean test for x, then if that is False, the expression y == 1 is tested.
This is due to operator precedence. The or operator has a lower precedence than the == test, so the latter is evaluated first.
However, even if this were not the case, and the expression x or y or z == 1 was actually interpreted as (x or y or z) == 1 instead, this would still not do what you expect it to do.
x or y or z would evaluate to the first argument that is 'truthy', e.g. not False, numeric 0 or empty (see boolean expressions for details on what Python considers false in a boolean context).
So for the values x = 2; y = 1; z = 0, x or y or z would resolve to 2, because that is the first true-like value in the arguments. Then 2 == 1 would be False, even though y == 1 would be True.
The same would apply to the inverse; testing multiple values against a single variable; x == 1 or 2 or 3 would fail for the same reasons. Use x == 1 or x == 2 or x == 3 or x in {1, 2, 3}.
Your problem is more easily addressed with a dictionary structure like:
x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]
As stated by Martijn Pieters, the correct, and fastest, format is:
if 1 in {x, y, z}:
Using his advice you would now have separate if-statements so that Python will read each statement whether the former were True or False. Such as:
if 0 in {x, y, z}:
mylist.append("c")
if 1 in {x, y, z}:
mylist.append("d")
if 2 in {x, y, z}:
mylist.append("e")
...
This will work, but if you are comfortable using dictionaries (see what I did there), you can clean this up by making an initial dictionary mapping the numbers to the letters you want, then just using a for-loop:
num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
if number in {x, y, z}:
mylist.append(num_to_letters[number])
The direct way to write x or y or z == 0 is
if any(map((lambda value: value == 0), (x,y,z))):
pass # write your logic.
But I dont think, you like it. :)
And this way is ugly.
The other way (a better) is:
0 in (x, y, z)
BTW lots of ifs could be written as something like this
my_cases = {
0: Mylist.append("c"),
1: Mylist.append("d")
# ..
}
for key in my_cases:
if key in (x,y,z):
my_cases[key]()
break
If you ARE very very lazy, you can put the values inside an array. Such as
list = []
list.append(x)
list.append(y)
list.append(z)
nums = [add numbers here]
letters = [add corresponding letters here]
for index in range(len(nums)):
for obj in list:
if obj == num[index]:
MyList.append(letters[index])
break
You can also put the numbers and letters in a dictionary and do it, but this is probably a LOT more complicated than simply if statements. That's what you get for trying to be extra lazy :)
One more thing, your
if x or y or z == 0:
will compile, but not in the way you want it to. When you simply put a variable in an if statement (example)
if b
the program will check if the variable is not null. Another way to write the above statement (which makes more sense) is
if bool(b)
Bool is an inbuilt function in python which basically does the command of verifying a boolean statement (If you don't know what that is, it is what you are trying to make in your if statement right now :))
Another lazy way I found is :
if any([x==0, y==0, z==0])
To check if a value is contained within a set of variables you can use the inbuilt modules itertools and operator.
For example:
Imports:
from itertools import repeat
from operator import contains
Declare variables:
x = 0
y = 1
z = 3
Create mapping of values (in the order you want to check):
check_values = (0, 1, 3)
Use itertools to allow repetition of the variables:
check_vars = repeat((x, y, z))
Finally, use the map function to create an iterator:
checker = map(contains, check_vars, check_values)
Then, when checking for the values (in the original order), use next():
if next(checker) # Checks for 0
# Do something
pass
elif next(checker) # Checks for 1
# Do something
pass
etc...
This has an advantage over the lambda x: x in (variables) because operator is an inbuilt module and is faster and more efficient than using lambda which has to create a custom in-place function.
Another option for checking if there is a non-zero (or False) value in a list:
not (x and y and z)
Equivalent:
not all((x, y, z))
Set is the good approach here, because it orders the variables, what seems to be your goal here. {z,y,x} is {0,1,3} whatever the order of the parameters.
>>> ["cdef"[i] for i in {z,x,y}]
['c', 'd', 'f']
This way, the whole solution is O(n).
I think this will handle it better:
my_dict = {0: "c", 1: "d", 2: "e", 3: "f"}
def validate(x, y, z):
for ele in [x, y, z]:
if ele in my_dict.keys():
return my_dict[ele]
Output:
print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e
If you want to use if, else statements following is another solution:
myList = []
aList = [0, 1, 3]
for l in aList:
if l==0: myList.append('c')
elif l==1: myList.append('d')
elif l==2: myList.append('e')
elif l==3: myList.append('f')
print(myList)
All of the excellent answers provided here concentrate on the specific requirement of the original poster and concentrate on the if 1 in {x,y,z} solution put forward by Martijn Pieters.
What they ignore is the broader implication of the question:
How do I test one variable against multiple values?
The solution provided will not work for partial hits if using strings for example:
Test if the string "Wild" is in multiple values
>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in {x, y, z}: print (True)
...
or
>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in [x, y, z]: print (True)
...
for this scenario it's easiest to convert to a string
>>> [x, y, z]
['Wild things', 'throttle it back', 'in the beginning']
>>> {x, y, z}
{'in the beginning', 'throttle it back', 'Wild things'}
>>>
>>> if "Wild" in str([x, y, z]): print (True)
...
True
>>> if "Wild" in str({x, y, z}): print (True)
...
True
It should be noted however, as mentioned by #codeforester, that word boundries are lost with this method, as in:
>>> x=['Wild things', 'throttle it back', 'in the beginning']
>>> if "rot" in str(x): print(True)
...
True
the 3 letters rot do exist in combination in the list but not as an individual word. Testing for " rot " would fail but if one of the list items were "rot in hell", that would fail as well.
The upshot being, be careful with your search criteria if using this method and be aware that it does have this limitation.
d = {0:'c', 1:'d', 2:'e', 3: 'f'}
x, y, z = (0, 1, 3)
print [v for (k,v) in d.items() if x==k or y==k or z==k]
This code may be helpful
L ={x, y, z}
T= ((0,"c"),(1,"d"),(2,"e"),(3,"f"),)
List2=[]
for t in T :
if t[0] in L :
List2.append(t[1])
break;
You can try the method shown below. In this method, you will have the freedom to specify/input the number of variables that you wish to enter.
mydict = {0:"c", 1:"d", 2:"e", 3:"f"}
mylist= []
num_var = int(raw_input("How many variables? ")) #Enter 3 when asked for input.
for i in range(num_var):
''' Enter 0 as first input, 1 as second input and 3 as third input.'''
globals()['var'+str('i').zfill(3)] = int(raw_input("Enter an integer between 0 and 3 "))
mylist += mydict[globals()['var'+str('i').zfill(3)]]
print mylist
>>> ['c', 'd', 'f']
One line solution:
mylist = [{0: 'c', 1: 'd', 2: 'e', 3: 'f'}[i] for i in [0, 1, 2, 3] if i in (x, y, z)]
Or:
mylist = ['cdef'[i] for i in range(4) if i in (x, y, z)]
Maybe you need direct formula for output bits set.
x=0 or y=0 or z=0 is equivalent to x*y*z = 0
x=1 or y=1 or z=1 is equivalent to (x-1)*(y-1)*(z-1)=0
x=2 or y=2 or z=2 is equivalent to (x-2)*(y-2)*(z-2)=0
Let's map to bits: 'c':1 'd':0xb10 'e':0xb100 'f':0xb1000
Relation of isc (is 'c'):
if xyz=0 then isc=1 else isc=0
Use math if formula https://youtu.be/KAdKCgBGK0k?list=PLnI9xbPdZUAmUL8htSl6vToPQRRN3hhFp&t=315
[c]: (xyz=0 and isc=1) or (((xyz=0 and isc=1) or (isc=0)) and (isc=0))
[d]: ((x-1)(y-1)(z-1)=0 and isc=2) or (((xyz=0 and isd=2) or (isc=0)) and (isc=0))
...
Connect these formulas by following logic:
logic and is the sum of squares of equations
logic or is the product of equations
and you'll have a total equation
express sum and you have total formula of sum
then sum&1 is c, sum&2 is d, sum&4 is e, sum&5 is f
After this you may form predefined array where index of string elements would correspond to ready string.
array[sum] gives you the string.
The most pythonic way of representing your pseudo-code in Python would be:
x = 0
y = 1
z = 3
mylist = []
if any(v == 0 for v in (x, y, z)):
mylist.append("c")
if any(v == 1 for v in (x, y, z)):
mylist.append("d")
if any(v == 2 for v in (x, y, z)):
mylist.append("e")
if any(v == 3 for v in (x, y, z)):
mylist.append("f")
It can be done easily as
for value in [var1,var2,var3]:
li.append("targetValue")
To test multiple variables with one single value: if 1 in {a,b,c}:
To test multiple values with one variable: if a in {1, 2, 3}:
Looks like you're building some kind of Caesar cipher.
A much more generalized approach is this:
input_values = (0, 1, 3)
origo = ord('c')
[chr(val + origo) for val in inputs]
outputs
['c', 'd', 'f']
Not sure if it's a desired side effect of your code, but the order of your output will always be sorted.
If this is what you want, the final line can be changed to:
sorted([chr(val + origo) for val in inputs])
You can use dictionary :
x = 0
y = 1
z = 3
list=[]
dict = {0: 'c', 1: 'd', 2: 'e', 3: 'f'}
if x in dict:
list.append(dict[x])
else:
pass
if y in dict:
list.append(dict[y])
else:
pass
if z in dict:
list.append(dict[z])
else:
pass
print list
Without dict, try this solution:
x, y, z = 0, 1, 3
offset = ord('c')
[chr(i + offset) for i in (x,y,z)]
and gives:
['c', 'd', 'f']
This will help you.
def test_fun(val):
x = 0
y = 1
z = 2
myList = []
if val in (x, y, z) and val == 0:
myList.append("C")
if val in (x, y, z) and val == 1:
myList.append("D")
if val in (x, y, z) and val == 2:
myList.append("E")
test_fun(2);
You can unite this
x = 0
y = 1
z = 3
in one variable.
In [1]: xyz = (0,1,3,)
In [2]: mylist = []
Change our conditions as:
In [3]: if 0 in xyz:
...: mylist.append("c")
...: if 1 in xyz:
...: mylist.append("d")
...: if 2 in xyz:
...: mylist.append("e")
...: if 3 in xyz:
...: mylist.append("f")
Output:
In [21]: mylist
Out[21]: ['c', 'd', 'f']
you can develop it through two ways
def compareVariables(x,y,z):
mylist = []
if x==0 or y==0 or z==0:
mylist.append('c')
if x==1 or y==1 or z==1:
mylist.append('d')
if x==2 or y==2 or z==2:
mylist.append('e')
if x==3 or y==3 or z==3:
mylist.append('f')
else:
print("wrong input value!")
print('first:',mylist)
compareVariables(1, 3, 2)
Or
def compareVariables(x,y,z):
mylist = []
if 0 in (x,y,z):
mylist.append('c')
if 1 in (x,y,z):
mylist.append('d')
if 2 in (x,y,z):
mylist.append('e')
if 3 in (x,y,z):
mylist.append('f')
else:
print("wrong input value!")
print('second:',mylist)
compareVariables(1, 3, 2)
The or does not work like that, as explained by this answer.
While the generic answer would be use
if 0 in (x, y, z):
...
this is not the best one for the specific problem. In your case you're doing repeated tests, therefore it is worthwhile to compose a set of these variables:
values = {x, y, z}
if 0 in values:
mylist.append("c")
if 1 in values:
mylist.append("d")
We can simplify this using a dictionary - this will result in the same values:
mappings = {0: "c", 1: "d", ...}
for k in mappings:
if k in values:
mylist.append(mappings[k])
Or if the ordering of the mylist is arbitrary, you can loop over the values instead and match them to the mappings:
mappings = {0: "c", 1: "d", ...}
for v in (x, y, z):
if v in mappings:
mylist.append(mappings[v])
Problem
While the pattern for testing multiple values
>>> 2 in {1, 2, 3}
True
>>> 5 in {1, 2, 3}
False
is very readable and is working in many situation, there is one pitfall:
>>> 0 in {True, False}
True
But we want to have
>>> (0 is True) or (0 is False)
False
Solution
One generalization of the previous expression is based on the answer from ytpillai:
>>> any([0 is True, 0 is False])
False
which can be written as
>>> any(0 is item for item in (True, False))
False
While this expression returns the right result it is not as readable as the first expression :-(
Here is one more way to do it:
x = 0
y = 1
z = 3
mylist = []
if any(i in [0] for i in[x,y,z]):
mylist.append("c")
if any(i in [1] for i in[x,y,z]):
mylist.append("d")
if any(i in [2] for i in[x,y,z]):
mylist.append("e")
if any(i in [3] for i in[x,y,z]):
mylist.append("f")
It is a mix of list comprehension and any keyword.
usage without if example:
x,y,z = 0,1,3
values = {0:"c",1:"d",2:"e",3:"f"} # => as if usage
my_list = [values[i] for i in (x,y,z)]
print(my_list)
FIRST, A CORRECTION TO THE OR CONDITIONAL:
You need to say:
if x == 0 or y == 0 or z == 0:
The reason is that "or" splits up the condition into separate logical parts. The way your original statement was written, those parts were:
x
y
z == 0 // or 1, 2, 3 depending on the if statement
The last part was fine --- checking to see if z == 0, for instance --- but the first two parts just said essentially if x and if y. Since integers always evaluate to True unless they're 0, that means the first part of your condition was always True when x or y didn't equal 0 (which in the case of y was always, since you had y = 1, causing your whole condition (because of how OR works) to always be True.
To avoid that, you need to make sure all parts of your condition (each side of the OR) make sense on their own (you can do that by pretending that the other side(s) of the OR statement doesn't exist). That's how you can confirm whether or not your OR condition is correctly defined.
You would write the statements individually like so:
if x == 0
if y == 0
if z == 0
which means the correct mergin with the OR keyword would be:
if x == 0 or y == 0 or z == 0
SECOND, HOW TO SOLVE THE PROBLEM:
You're basically wanting to check to see if any of the variables match a given integer and if so, assign it a letter that matches it in a one-to-one mapping. You want to do that for a certain list of integers so that the output is a list of letters. You'd do that like this:
def func(x, y, z):
result = []
for integer, letter in zip([0, 1, 2, 3], ['c', 'd', 'e', 'f']):
if x == integer or y == integer or z == integer:
result.append(letter)
return result
Similarly, you could use LIST COMPREHENSION to achieve the same result faster:
def func(x, y, z):
return [
letter
for integer, letter in zip([0, 1, 2, 3], ['c', 'd', 'e', 'f'])
if x == integer or y == integer or z == integer
]
To test multiple variables against a single value:
Wrap the variables in a set object, e.g. {a, b, c}.
Use the in operator to test if the value is stored in any of the variables.
The in operator will return True if the value is stored in at least one of the variables.
# ✅ test multiple variables against single value using tuple
if 'a' in (a, b, c):
print('value is stored in at least one of the variables')
# ---------------------------------------------------------
# ✅ test multiple variables against single value using tuple
if 'a' in {a, b, c}:
print('value is stored in at least one of the variables')
# ---------------------------------------------------------
# ✅ test multiple variables against single value (OR operator chaining)
if a == 'a' or b == 'a' or c == 'a':
print('value is stored in at least one of the variables')
Related
split(L,X,Y):-append(X,Y,L).
creates 4 splits as follows:
X = [],
Y = [1, 2, 3] ;
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
X = [1, 2, 3],
Y = [] ;
I want to eliminate the empty list created during split and keep only combinations which do not have empty list that is
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
You can first specify the pattern for X and Y, by unifying these with a "cons":
split(L, X, Y) :-
X = [_|_],
Y = [_|_],
append(X, Y, L).
The advantage of using this approach, is that you will probably safe some cycles, since append/3 will not propose certain solutions that are empty lists, that then have to be filtered out.
In order to solve your problem, as said in the comments, you have to add a condition that checks if X or Y are empty, in this way:
split(L,X,Y):-
append(X,Y,L),
x\=[],
Y\=[].
Why the check is done after append/3? X = [] is true because X can be unified with [] when it is still uninstantiated. When you call split/3, initially X and Y are uninstantiated (if you use the tracer you can see something like _4604\=[]): X = [] succeds and so the negation fails and the program returns false if you put X\=[] and Y\=[] before append/3.
To better understand, i suggest you to read this article.
I am having a scope issue, and I know how I would solve this in Java, but Python is giving me some issues. Say I have a code as follows:
a = 1
b = 2
c = 3
list1 = [a,b,c]
list2 = [b,c]
b += 1
print list1
print list2
This code does not change the value inside the lists, and there is an easy workaround for the simple example I've given, but the code I am trying to write has 10+ lists that all have different meanings and are used in different ways, but need to communicate with each other and have all the same values for a,b,c. I need to be able to change the variable a,b,c and have all the lists update as well, is there any other way besides writing out the update for each list?
You cannot store the integers by reference, such that incrementing the value in one place causes all other values to be updated. This is because ints are immutable, so changing their value causes a reference change.
>>> a = 5
>>> b = 1
>>> x = [a, b]
>>> id(b)
140508116572264
>>> id(x[1])
140508116572264
>>> b += 1
>>> id(b)
140508116572240
You can see the id of b changes after the increment, so the "b" in the loop and the "b" outside aren't the same.
What you can do, is define a wrapper class for your ints.
class MyInteger:
def __init__(self, value):
self.value = value
Now, build your lists with your MyIntegers:
a = MyInteger(1)
b = MyInteger(2)
c = MyInteger(3)
list1 = [a, b, c]
list2 = [b, c]
Now, when you increment the value of b, you can see the changes are reflected in the lists.
print([x.value for x in list1])
b.value += 1
print([x.value for x in list1])
This prints:
[1, 2, 3]
[1, 3, 3]
I'm starting to code in python and I came across this code snippet:
for [x, y] in L:
for ix in range(-1, 2):
for iy in range(-1, 2):
cir = pylab.Circle((x + ix, y + iy), radius=sigma, fc='r')
pylab.gca().add_patch(cir)
at the line 1 I can not understand what is happening because I had never seen anything like it in another programming language. How this works?
for [x, y] in L:
[x, y] is a list? i dont know.
L must be a sequence of lists (or tuples) with two elements, which can be iterated over. So whenever for [x,y] in L: is executed, it picks each item in th sequence one by one and enters into the loop.
let the sequence be L = [[2,3], [4,5], ['Jeff', 7]]
Now here what will happen when for [x,y] in L: will be executed is :- first list in the sequence [2,3] will be picked up and assigned as x and y respectively. And in the next iteration x and y will get the value 4 & 5 respectively. Like wise in third iteration x will be Jeff and y will be 7.
L = [[2,3], [4,5], ['Jeff', 7]]
count = 0
for [x,y] in L:
count += 1
print " Iteration :- %d, \t x :- %s, \t y:- %s" %(count, str(x), str(y))
Yes, [x, y] is a list with two elements. For your loop to work, L must be a list (or other iterable data structure) that contains a bunch of lists with two elements. Each time through the loop one of those lists is copied into [x, y], then the individual values of x and y are used in the body of the loop.
Try this and see if it makes sense:
L = [ [1, 2], [3, 4] ]
for [x, y] in L:
print x
print y
Lets say I have the list below:
list1=[1,2,4,6,8,3,2,5,8,4,2]
I want to return the integer, 2, because 8 is the maximum value and there are two 8s in the list. How can I do this? Edit: I also want to assume that the maximum number in the list can be any negative or non-negative number including zero.
Well you can use something like this:
list1=[1,2,4,6,8,3,2,5,8,4,2]
print list1.count(max(list1))
ans = 0
mx = 0
for x in list1:
if x > mx:
mx = x
ans = 1
elif x == mx :
ans += 1
print ans
assume max number is bigger than 0, otherwise you should initial mx with the negative infinity
>>> list1=[1,2,4,6,8,3,2,5,8,4,2]
>>> x = max(list1)
>>> l = []
>>> for i in list1:
if i == x:
l.append(i)
>>> l
[8, 8]
>>> len(l)
2
OR
>>> list1=[1,2,4,6,8,3,2,5,8,4,2]
>>> x = max(list1)
>>> result = len(filter(lambda i: i == x, list1))
>>> result
2
I would like to find out programatically if a SymPy expression contains a symbol. E.g., for
import sympy
x = sympy.Symbol('x')
y = sympy.Symbol('y')
a = 4 + x**2 + y
b = 4 + y**2
a contains both x and y, b contains only y.
>>> x in a.free_symbols, y in a.free_symbols
(True, True)
>>> x in b.free_symbols, y in b.free_symbols
(False, True)
You can also use .atoms(Symbol) to check that. atoms(Symbol) differs from .free_symbols in some cases. free_symbols doesn't return dummy symbols, like integration variables.
it's usually what you want, since expressions don't mathematically depend on dummy symbols
example:
>>> Integral(f(x), (x, 0, 1)).atoms(Symbol)
set([x])
>>> Integral(f(x), (x, 0, 1)).free_symbols
set([])