Help Creating a Function

I have the following list:

people = [(‘Jake’, 36, ‘M’),(‘Rose’, 24, ‘F’),(‘Derek’, 78, ‘F’),(‘Alan’, 17, ‘M’),(‘Sarah’, 14, ‘F’)]

I want to create a function where it will only bring back a list of names for those who are >= 18 years of age. I currently have the following but I’m struggling to complete the code:

def adults(members):

  people = []

    for entry in members:

        if entry[1] >= 18:
        name.append(name[0])
return [name]

You are on the right track, but a few things are missing:

  • You try to append something to a variable name that does not yet exist. I think you mean to append to people instead. Similarly, you wish to append name[0] when you mean entry[0].
  • The return statement is not right: you should return people.
  • This is possibly a side-effect of pasting, but the indentation isn’t quite right.

A fixed version would be:

def adults(members):
    people = []

    for entry in members:
        if entry[1] >= 18:
            people.append(entry[0])

    return people

This can actually be achieved in much less code using a list comprehension. It may be more difficult for you to read at first if you are a beginner, but it will be very helpful to get acquainted with them:

def adults(members):
    return [entry[0] for entry in members if entry[1] >= 18]
4 Likes

Bec,

I see you already have a reply, including the list comprehension that may be ahead of what you are expected to use now.

I will try another approach and hopefully one that is at a lower level, if that is what you need. If not, then you alredy know enough.

First, perhaps as an artifact, I am getting the wrong type of quotes in the one-liner you sent to populate the file as it was not in the ```python format of the rest of your code.

people = [(‘Jake’, 36, ‘M’),(‘Rose’, 24, ‘F’),(‘Derek’, 78, ‘F’),(‘Alan’, 17, ‘M’),(‘Sarah’, 14, ‘F’)]

I had to replace all the open/close single quotes to get:

people = [('Jake', 36, 'M'),('Rose', 24, 'F'),('Derek', 78, 'F'),('Alan', 17, 'M'),('Sarah', 14, 'F')]

It is a list of tuples containing what seems to be a name/age/gender and perhaps could have been written a tad more clearly as:

people = [
  ('Jake', 36, 'M'),
  ('Rose', 24, 'F'),
  ('Derek', 78, 'F'),
  ('Alan', 17, 'M'),
  ('Sarah', 14, 'F')]

The above is not important but it helps to see the internal structure so a different approach is possible.

If you loop over this, you can do what you did and get one tuple at a time and then use something like entry[1] to refer to the age in what is the second part of each tuple, but just for the heck of it, consider this code in which you deconstruct each tuple:

def adults(members):

  people = []

  for name, age, gender in members:
    if age >= 18:
      people.append(name)

  return people

I am assuming from your code that you only want the names, not the full tuples. When I run the code, I get this result:

>>> adults(people)
['Jake', 'Rose', 'Derek']

Note that if you wanted to return the entire tuples that matched, use this instead:

  def adults_tup(members):

  people = []

  for name, age, gender in members:
    if age >= 18:
      people.append((name, age, gender))

  return people

This version returns a subset of the list:

>>> adults_tup(people)
[('Jake', 36, 'M'), ('Rose', 24, 'F'), ('Derek', 78, 'F')]

If you really don’t want the gender, some people would replace it with a single underscore to mean you don’t care.

The above is not a better method but just an alternate to what Alex showed. He went with your method of using subscripting and that is fine. The method I am showing may be more readable to some, or more confusing if they do not understand how python supports multiple assignments as shown.

If you have learned how to use a list comprehension, I supply my variant of what Alex suggests, again, not as better but as another way of looking at it. It only cares about name and age and ignores gender and is really internally seen as automatically building a list and returning it in a more compressed and hopefully readable way:

def adults(members):
    return [name for name, age, _ in members if age >= 18]

But note that this function is so short as a one-liner that it may not be needed at all if you use it only once. You could just have:

>>> old_enough = [name for name, age, _ in people if age >= 18]
>>> old_enough
['Jake', 'Rose', 'Derek']

:underage:

>>> [name for name, age, _ in people if age < 18]
['Alan', 'Sarah']
2 Likes

Hi,

Thank you for your help, I’m really struggling with learning how to do functions with a tuple, I find data frames much easier. If you have any guidance where I can learn to create definitions from tuples I will really appreciate it.

At the moment, I am now trying to create a function where if I input M or F it will give me the average age for that gender. I also want to make it so if a different letter is input, it will state no matches found.

When I type M, it brings me back Jack’s age, and if I type Z it also brings back Jack’s age. It’s like the formula is just appending index 1 and not looking at the rest of the data set. I’m also not sure why the else statement also isn’t working where I’ve specified if entry is ‘M’ or ‘F’

With my formula, it seems to just bring back the a

people = [(‘Jack’, 36, ‘M’),(‘Rose’, 24, ‘F’),(‘Dotty’, 78, ‘F’),(‘Alan’, 17, ‘M’),(‘Sarah’, 14, ‘F’)]

def average_age(members, gender):

 members = []

gender = 'M','F'

for entry in people:
    if entry [2] =='M'or 'F':
        members.append(entry[1])
        return sum(members) / len(members)
    else:
        return 'No matches found.'

Bec,

I see possibly places you are using other aspects of python in ways that mean something else to the interpreter. I am heading out so here is one example:

if entry [2] =='M'or 'F':

I would leave a space but the real issue is you are using or in a way that means this:

# Wrong use of or which is seen this way
if (entry [2] =='M') or ('F'):

This says check if the third item is ‘M’ and if it is, return True.

Only if it does not match M, do you return the character string ‘F’ and since the if statement wants a truthy result that looks Boolean, it sees a nonempty string as True. Hence any other gender is the same.

What you wanted was two comparisons as in:

if (entry [2] =='M') or (entry[2]) == 'F'):

Alternately there are ways to use the in keyword here since you already made a tuple called gender:

gender = 'M','F'

if entry [2] in gender:

This is an easy way to ask if any of multiple matches exist. There is also a not in if you want to invert the logic.

Note that I only showed a few lines and you need to make the changes including the rest of your code.

As to your return values, note you are returning a decimal like 0.55 not 55% which is fine, as a floating point number and on failure, returning an error text. Anything calling this function needs to be prepared to use what is returned appropriately.

Hello,

note that when working with tuples or lists, each element has an implied index, and each index count begins at zero (0). For example, the tuple a_tuple = ('a', 'b', 'c', 'd') has four elements having the implied indeces of 0, 1, 2, and 3. So,

a_tuple[0] = 'a'
a_tuple[1] = 'b'
a_tuple[2] = 'c'
a_tuple[3] = 'd'

Now, if you have tuples with nested tuples, of which your person tuple has, you will have to index it two dimensionally. The first index corresponds to the nth tuple in the person tuple, and the 2nd index corresponds to the nth element of a tuple.

For example, if you want to obtain Dotty's age, you would index it as: people[2][1]. You can verify this by printing her age as in: print("Dotty's age is: ", people[2][1])

For this, you can try something like this:

def ave_age(list_of_people, gender):

    if gender in ('M', 'F'): # Verify valid entry

        count = 0
        sums = 0

        for info in list_of_people:

            if info[2] == gender:

                count += 1
                sums += info[1]

        print(f'{gender} average age (years) is: ', round(sums / count, 1))

    else:
        print('Not a valid entry.  Try again.')

ave_age(people, 'F')

Note that in this test function, as soon as we enter, we first check if a valid gender entry has been entered (ensures entry is valid - in case user accidentally typed in a value other than M or F). If incorrect entry is entered, we alert the user to try again. Otherwise, we enter the for iteration loop.

Thereafter, we include the conditional statement where we compare the entered gender against those in the entered list. If during each iteration there is a match, we add the age to the sums variable and keep track of the times the condition was met.

Once the iteration is complete, we take the average. Note that I have used the round function so that we limit the decimal places to only one.

A good book to learn Python fundamentals is: Learning Python by Mark Luntz. This book goes in depth regarding tuples and functions among many other topics.

Good luck!

In additional to what others said, one thing that could help clarify your code is to also use tuple unpacking. If you have Python code like this:

x = ('Alice', 18, 'F')
name = x[0]
age = x[1]
gender = x[2]

…then Python lets you do this:

x = ('Alice', 18, 'F')
name, age, gender = x

So it might help clarify your code if you write it like this:

def adults(members):

people = []

for entry in members:
    name, age, gender = entry
    if age >= 18:
        people.append(name)
return [name]

I think perhaps the name.append(name[0]) might have happened because you got mixed up with some of the variables.

Also, remember that a new, more-indented block ALWAYS starts on the next line after a statement that ends with a colon, like the def, for, and if statements in your code.