a9302c
a9302c

Reputation: 241

Comparing items through a tuple in Python

I am given an assignment when I am supposed to define a function that returns the second element of a tuple if the first element of a tuple matches with the argument of a function.

Specifically, let's say that I have a list of student registration numbers that goes by: particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))

And I have defined a function that is supposed to take in the argument of reg_num, such as "S12345", and return the name of the student in this case, "John". If the number does not match at all, I need to print "Not found" as a message. In essence, I understand that I need to sort through the larger tuple, and compare the first element [0] of each smaller tuple, then return the [1] entry of each smaller tuple. Here's what I have in mind:

def get_student_name(reg_num, particulars):
    for i in records:
        if reg_num == particulars[::1][0]:
            return particulars[i][1]
        else:
            print("Not found")

I know I'm wrong, but I can't tell why. I'm not well acquainted with how to sort through a tuple. Can anyone offer some advice, especially in syntax? Thank you very much!

Upvotes: 3

Views: 268

Answers (3)

Stef
Stef

Reputation: 15504

for loops in python

Gilad Green already answered your question with a way to fix your code and a quick explanation on for loops.

Here are five loops that do more or less the same thing; I invite you to try them out.

particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))

for t in particulars:
  print("{} {}".format(t[0], t[1]))

for i in range(len(particulars)):
  print("{}: {} {}".format(i, particulars[i][0], particulars[i][1]))

for i, t in enumerate(particulars):
  print("{}: {} {}".format(i, t[0], t[1]))
  
for reg_value, student_name in particulars:
  print("{} {}".format(reg_value, student_name))
  
for i, (reg_value, student_name) in enumerate(particulars):
  print("{}: {} {}".format(i, reg_value, student_name))

Using dictionaries instead of lists

Most importantly, I would like to add that using an unsorted list to store your student records is not the most efficient way.

If you sort the list and maintain it in sorted order, then you can use binary search to search for reg_num much faster than browsing the list one item at a time. Think of this: when you need to look up a word in a dictionary, do you read all words one by one, starting by "aah", "aback", "abaft", "abandon", etc.? No; first, you open the dictionary somewhere in the middle; you compare the words on that page with your word; then you open it again to another page; compare again; every time you do that, the number of candidate pages diminishes greatly, and so you can find your word among 300,000 other words in a very small time.

Instead of using a sorted list with binary search, you could use another data structure, for instance a binary search tree or a hash table.

But, wait! Python already does that very easily!

There is a data structure in python called a dictionary. See the documentation on dictionaries. This structure is perfectly adapted to most situations where you have keys associated to values. Here the key is the reg_number, and the value is the student name.

You can define a dictionary directly:

particulars = {'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}

Or you can convert your list of tuples to a dictionary:

particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))
particulars_as_dict = dict(particulars)

Then you can check if an reg_number is in the dictionary, with they keyword in; you can return the student name using square brackets or with the method get:

>>> particulars = {'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}
>>> 'S23456' in particulars
True
>>> 'S98765' in particulars
False
>>>
>>> particulars['S23456']
'Max'
>>> particulars.get('S23456')
'Max'
>>> particulars.get('S23456', 'not found')
'Max'
>>>
>>> particulars['S98765']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'S98765'
>>> particulars.get('S98765')
None
>>> particulars.get('S98765', 'not found')
'not found'

Upvotes: 1

NateB
NateB

Reputation: 509

Another approach, provided to help learn new tricks for manipulating python data structures:

You can turn you tuple of tuples:

particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))

into a dictionary:

>>> pdict = dict(particulars)
>>> pdict
{'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}

You can look up the value by supplying the key:

>>> r = 'S23456'
>>> dict(pdict)[r]
'Max'

The function:

def get_student_name(reg, s_data):
    try:
        return dict(s_data)[reg]
    except:
        return "Not Found"

The use of try ... except will catch errors and just return Not Found in the case where the reg is not in the tuple in the first place. It will also catch of the supplied tuple is not a series of PAIRS, and thus cannot be converted the way you expect.

You can read more about exceptions: the basics and the docs to learn how to respond differently to different types of error.

Upvotes: 2

Gilad Green
Gilad Green

Reputation: 37299

When you write for i in particulars, in each iteration i is an item of the collection and not an index. As such you cannot do particulars[i] (and there is no need - as you already have the item). In addition, remove the else statement so to not print for every item that doesn't match condition:

def get_student_name(reg_num, particulars):
    for i in particulars:
        if reg_num == i[0]:
            return i[1]
    print("Not found")

If you would want to iterate using indices you could do (but less nice):

for i in range(len(particulars)):
    if reg_num == particulars[i][0]:
        return particulars[i][1]

Upvotes: 4

Related Questions