Language: Python(vers3.3); If statements inside while and if statements - python

My program is unable to go into the last of my if/else statement.
My code:
def main_prog():
while True:
data_dict = {'123': 'viksun', '111': ['tord'], '333': ['test']} # Data storage.
print (data_dict) # Track-print
prompt = input('Enter command >>> ').split(" ")
if prompt[0] == 'lookup':
B_value = name_lookup_return_boolean(data_dict, prompt[1])
if B_value == True:
print (prompt[1],"'s number is:", name_lookup(data_dict, prompt[1]))
else:
print("The name:" ,prompt[1], "do not exist, please try a different name")
Data struction of the dictionary: data_dict
data_dict = {'123': ['name1'], '111': ['tord'], '333': ['test']} # Data storage.
Function descriptions:
- name_lookup_returns_boolean(data_dict, name) returns a boolean value: True if the name is located in the dictionary and False if the name does not exist.
- name_lookup returns the key that corresponds to the specific name.
The functions have been tested separately from the whole program, so they are working. If you need them, I can also post them.
I can't get the program to run the last else statement in the program. This is going to run if the name does not exist in the dictionary: data_dict.
Here is the implementation of the two functions:
def name_lookup(data_dict, name):
for key, value in data_dict.items():
if name in value:
return key
def name_lookup_return_boolean(data_dict, name):
for value in data_dict.items():
if name in value:
return True
else:
return False
This is the variation I have tried to use_but with no sucess:
def name_lookup_version_02(data_dict, name):
for value in data_dict.values():
if name in value:
return True
else:
return False

In this line:
if B_value == True:
I'm guessing that B_value holds a true value, but not True. Try this instead:
if B_value:

The problem is in your name_lookup_return_boolean function. You are returning True for both conditions. Also you should be enumerating both key and value otherwise value will be assigned a tuple.
It should look like this:
def name_lookup_return_boolean(data_dict, name):
for key,value in data_dict.items():
if name in value:
return True
UPDATE: After testing, I realised previous answer was wrong - was only matching the first value

Related

How can I confirm a value is in nested dictionary or not

enter image description hereI have been trying to write a code that if a specific value is in a triple nested dictionary (most inner side) or not however I keep having string indices must be integers even though It is a dictionary.
dictionary is like:
{'Mo': {'10.00': 'COMP100'},
'Tu': ' ',
'We': {'12.00': 'UNIV199'},
'Th': ' ',
'Fr': ' '}
and I am trying a class code which is not in the dictionary so It should warn the user.
like "ECON201"
For type consistency, I recommend using an empty dictionary {} instead of ' ' for empty days. With that in mind, suppose we have the following:
sched = {'Mo': {'10.00': 'COMP100'},
'Tu': {},
'We': {'12.00': 'UNIV199'},
'Th': {},
'Fr': {}}
# code = "COMP100"
code = "ECON201"
Then, we could search for the code as follows:
found = False
for d in sched.values():
for s in d.values():
if s == code:
found = True
break
if found:
break
if found:
print('code found in schedule')
else:
print('code not found in schedule')
Alternatively, you can avoid dealing with breaks and storing booleans if you define a function. For instance,
def is_in(sch,c):
for d in sch.values():
for s in d.values():
if s == c:
return True
return False
if is_in(sched,code):
print('code found in schedule')
else:
print('code not found in schedule')
Alternatively, here's a recursive version of the function that works for arbitrarily many layers of nesting.
def is_in(sch,c):
for v in sch.values():
if isinstance(v,dict):
if is_in(v,c):
return True
elif v == c:
return True
return False
if is_in(sched,code):
print('code found in schedule')
else:
print('code not found in schedule')
On the other hand, from your image, it seems that you're looking for a way to remove a course from a schedule. To that end, consider the following.
sched = {'Mo': {'10.00': 'COMP100'},
'Tu': {},
'We': {'12.00': 'UNIV199'},
'Th': {},
'Fr': {}}
# code = "COMP100"
code = "ECON201"
# print(sched)
def rem(c,sch):
for k in sch.copy():
if isinstance(sch[k],dict):
rem(c,sch[k])
else:
if sch[k]==c:
del sch[k]
rem(code,sched)
print(sched)
In the case that the course does not appear, nothing happens. If the course is found, then all instances of that course are deleted.

Access an iterator in 'for' loop, before the loop

I am trying to access an iterator 'obj' before the 'for' loop like this
class MyClass:
CLASS_CONST1 = 'some_rand_const'
def __init__(self, type, age):
self.type = type
self.age = age
var1 = 5
age = 7
# # I tried to individually add the following lines here, none of them work
# obj = MyClass
# obj = MyClass()
condition = obj.type == MyClass.CLASS_CONST1
if var1 > 10:
condition = obj.type == MyClass.CLASS_CONST1 and obj.age == age
list_of_objects = [MyClass('rand1', 'rand2'), MyClass('rand1', 'rand2'), MyClass('rand1', 'rand2')]
for obj in list_of_objects:
if condition:
# do some stuff
pass
The issue is that it is accessed before it is defined (it gets defined in the for loop). And I dont want introduce the condition lines inside the 'for' loop because the lines would be executed in every iteration, and there is no need for that.
The idea is that all this goes into a function and 'var1' and 'age' are arguments of the function.
obj = MyClass just assigns the class object (not instance) to another variable. obj = MyClass() will throw an error because you haven't provided values for type and age which are required in __init__. Did you try obj = MyClass(var1, age) ? You did it later for list_of_objects.
Anyway, you've tried to create condition as a variable that is supposed to apply itself during the iteration. That's not how Python works. It's given a static value when it's evaluated the one time. To have it apply to all objects, have condition as a function which either take the object or the two variables type and var as parameters and then return the result of the check:
var1 = 5
age = 7
def condition(obj):
# will return the True/False result of the check below
return obj.type == MyClass.CLASS_CONST1 and obj.age == age
for obj in list_of_objects:
if condition(obj): # call the function with that object
# do some stuff
pass
From your code, it's unclear what you wanted in condition. Maybe it was this?
var1 = 5 # or put these inside `condition` so they are local
age = 7 # to condition and not globals.
# Or pass them in as parameters and modify `condition` to accept
# the additional params
def condition(obj):
result = obj.type == MyClass.CLASS_CONST1
if result and var1 > 10:
# don't re-check `obj.type == MyClass.CLASS_CONST1`
result = obj.age == age
return result
You declare condition as a simple boolean variable, while its value has to depend on the current values of obj. You could use a bunch of functions and assign condition to the relevant one, or as you conditions are simple, you could use lambdas:
condition = obj.type == MyClass.CLASS_CONST1
if var1 > 10:
condition = lambda obj: obj.type == MyClass.CLASS_CONST1 and obj.age == age
else:
condition = lambda obj: obj.type == MyClass.CLASS_CONST1
and then use it as a variable function:
for obj in list_of_objects:
if condition(obj):
# do some stuff
pass

Check multiple keys in a dictionary for existence and value

I would like to do something only if an object has two keys with given values:
tel = ...
nam = ...
for obj in listofobjs:
for key, val in obj.items():
if (key == 'tel' and val == tel) and \
(key == 'nam' and val == name):
# do something...
Which won't work since key and value can't be two values at the same time.
Here's one way to do it without having to use .items():
for obj in listofobjs:
if 'tel' in obj and 'nam' in obj and obj['tel']==tel and obj['nam']==nam:
...
Or you could ask for forgiveness provided all dictionary access in the if block are safe:
for obj in listofobjs:
try:
if obj['tel']==tel and obj['nam']==nam:
...
except KeyError:
pass
You don't need to loop over the .items() to do this.
for obj in listofobjs:
if (obj.get('tel', None) == tel) and (obj.get('nam', None) == nam):
Just use .get to get the key, so that you don't get a KeyError if the key doesn't exist.
.get returns None by default, but I'm specifying it here to highlight the ability to use a different default value. If you want to use None as the default, you can leave out the second parameter from the .get call.
Replace None with a value that you know will never be a valid value for tel or nam.

How to loop through keys in a dict to find the corresponding value?

When a user enters a name (e.g. "Jim") as an argument for an instance of my "Test" class, the def find function is called and for-loops through all the names in the dict matching "Jim". If def find finds the key word "Jim" in the dict, then it should print out the corresponding value. But when I run the code it just says "None". What do I need to change so that invoking def find results in the print statement 'worked'??
class Test(object):
def __init__(self, x=0): # error in (def find)?
self.x = x
c = None # error while looping in the for loop?
users = {
'John': 1,
'Jim': 2,
'Bob': 3
}
def find(self, x): # The user is supposed to type in the name "x"
for self.c in self.users: # it goes through the dictionary
if x == self.users[self.c]: # If x is equal to key it prints worked
print('worked')
else:
pass
beta = Test()
print(beta.find('Jim'))
#nk001,
I think this is a little more like what you are trying for:
class Test(object):
def __init__(self, x=0):
self.x = x # <-- indent the __init__ statements
users = { # <-- users = {
'John': 1, # KEY: VALUE,
'Jim': 2, # KEY: VALUE,
'Bob': 3 # KEY: VALUE,
} # }
def find(self, x): # <-- The user passes the "x" argument
for i in self.users: # <-- Now it goes through the dictionary
if x == i: # <-- If ARGV('x') == KEY
return 'worked' # <-- Then RETURN 'worked'
else:
pass
beta = Test()
print(beta.find("Jim"), beta.users["Jim"])
There's a couple different ways to get the 'worked' msg and the corresponding Value printed, this is just an example to demonstrate accessing the dict[KEY] to get the VALUE.
Also, I'm just assuming you meant an if/else block, and not a for/else? Indentation is critical w/Python. Also, your original script was returning None because there was no explicit return in your for loop - hence, when the function is called in the printing statement print(beta.find('Jim')) when the function finishes it returns nothing ("None"). Hope that helps!
I write a worked code:
class Test(object):
users = {
'John': 1,
'Jim': 2,
'Bob': 3
}
def __init__(self, x=0): # So I don't get an error in (def find)
self.x = x
def find(self, x): # The user is suppose to type in the name "x"
for name in Test.users.keys(): # it goes through the dictionary
if x == name: # If x is equal to key it prints worked
print('worked', self.users[name])
else:
pass
beta = Test()
beta.find('Jim')
You don not need the self.c.
The users is a class variable, you need to visit it by Test.users.
Your names is stored as the keys of the dict. So you need to get them by Test.users.keys()
The statement print(beta.find('Jim')) will print the return value of the find. But you don't return a value manually, you will get a None in your output.

How to Build a dictionary from a text file in Python

I have a text file with entries that look like this :
JohnDoe
Assignment 9
Reading: NO
header: NO
HW: NO
Solutions: 0
show: NO
Journals: NO
free: NO
Finished: NO
Quiz: 0
Done
Assignment 3
E-book: NO
HW: NO
Readings: NO
Show: 0
Journal: NO
Study: NO
Test: NO
Finished: NO
Quiz: 0
Done
This is a small sample. The file has several students in it. Each student has two assignments under their name and they only pass if the line that starts with "Finished" in each assignment reads "Finished: YES". All of the data under each assignment is disorganized, but somewhere under each assignment a line will say "Finished: YES (or NO)" I need a way to read the file and say whether or not any of the students have passed. So far, I have
def get_entries( file ):
with open( "dicrete.txt.rtf", 'rt') as file:
for line in file:
if "Finished" in line:
finished, answer = line.split(':')
yield finished, answer
# dict takes a sequence of `(key, value)` pairs and turns in into a dict
print dict(get_entries( file ))
I can only get this code to return a single entry (the first "Finished" it reads as key and "YES or NO" as value, which is what I want, but I want it to return Every line in the file that that starts with "Finished". So the sample data I provided I want to return a dict with 2 entries {Finished:"NO" , Finished:"NO"}
Dictionaries can only store one mapping per key. So, you can never have a dictionary that has two different entries for the same key.
Consider using a list of two-tuples instead, like [("Finished", "NO"), ("Finished", "NO")].
Sounds like you need a better data model! Let's look at that, shall we?
Let's define an Assignment class that we can call with all the lines of text between Assignment: # and Finished: YES/NO.
class Assignment(object):
def __init__(self, id, *args, **kwargs):
self.id = id
for key,val in kwargs.items():
setattr(self, key.lower(), val)
finished = getattr(self, 'finished', None)
if finished is None:
raise AttributeError("All assignments must have a 'finished' value")
else:
self.finished = True if finished.lower() == "yes" else False
#classmethod
def from_string(cls, s):
"""Builds an Assignment object from a string
a = Assignment.from_string('''Assignment: 1\nAttributes: Go Here\nFinished: yes''')
>>> a.id
1
>>> a.finished
True"""
d = dict()
id = None
for line in s.splitlines():
key,*val = map(str.strip, line.split(":"))
val = ' '.join(val) or None
if key.lower().startswith('assignment'):
id = int(key.split()[-1])
continue
d[key.lower()] = val
if id is not None:
return cls(id, **d)
else:
raise ValueError("No 'Assignment' field in string {}".format(s))
Once you have your model, you'll need to parse your input. Luckily this is actually pretty simple.
def splitlineson(s, sentinel):
"""splits an iterable of strings into a newline separated string beginning with each sentinel.
>>> s = ["Garbage", "lines", "SENT$", "first", "group", "SENT$", "second", "group"]
>>> splitlineson(s, "SENT$")
iter("SENT$\nfirst\ngroup",
"SENT$\nsecond\ngroup")"""
lines = []
for line in s:
if line.lower().strip().startswith(sentinel.lower()):
if any((sentinel.lower() in line.lower() for line in lines)):
yield "\n".join(lines)
lines = [line.strip()]
else:
if line:
lines.append(line.strip())
yield "\n".join(lines)
with open('path/to/textfile.txt') as inf:
assignments = splitlineson(inf, "assignment ")
assignment_list = [Assignment.from_string(a) for a in assignments]

Categories