How to select only last names?

If you are referencing -1 of a string it will return the last letter in the string, for example: str1 = ‘hello there’ , str1[-1] = e
if you are referencing -1 of a list containing strings it will return the last string in the list, for example: lst1 = [‘hello’, ‘there’] , lst1[-1] = there

9 Likes

Hi, first time poster. I had to see the solution for this one, and was wondering how an alternative would work so I tried the below:

author_last_names =
for name in author_names:
author_last_names += name.split()[-1]

when I print author_last_names it prints each letter of the last names like: [‘L’, ‘o’, ‘r’, ‘d’, ‘e’, ‘M’, ‘i’, ‘s’, ‘t’, ‘r’, ‘a’, ‘l’, ‘T’, ‘o’, ‘o’, ‘m’, ‘e’, ‘r’, ‘Q’, ‘i’, ‘W’, ‘h’, ‘i’, ‘t’, ‘m’, ‘a’, ‘n’, ‘S’, ‘i’, ‘l’, ‘v’, ‘e’, ‘r’, ‘s’, ‘t’, ‘e’, ‘i’, ‘n’, ‘B’, ‘o’, ‘u’, ‘l’, ‘l’, ‘o’, ‘s’, ‘a’, ‘S’, ‘u’, ‘r’, ‘a’, ‘i’, ‘y’, ‘y’, ‘a’, ‘H’, ‘u’, ‘g’, ‘h’, ‘e’, ‘s’, ‘R’, ‘i’, ‘c’, ‘h’, ‘G’, ‘i’, ‘o’, ‘v’, ‘a’, ‘n’, ‘n’, ‘i’]

How would I correct this code?/Why does it split at each letter?

Thanks!

2 Likes

because of [-1]. Which gives you the last letter of a string or list

3 Likes

I’m having trouble understanding why this is outputting every letter in each string in the list instead of a single string per index value.

When I print the range(len(new_list))) I get a range of 0,25 but the output for new_list gives me a list containing each individual letter in each string.

Also, I realize that this method will not give me a correct list of last names, but I still would like to know why its giving the result it does. TIA!

authors = "Audre Lorde, William Carlos Williams, Gabriela Mistral, Jean Toomer, An Qi, Walt Whitman, Shel Silverstein, Carmen Boullosa, Kamala Suraiyya, Langston Hughes, Adrienne Rich, Nikki Giovanni"

author_names = authors.split(',')

print(author_names)

#Split the authors names 
def first_last_split(list):
  new_list = []
  for i in list:
    new_list += i.split()
  return new_list

print(first_last_split(author_names))

#Check new_list range value 
new_list = (first_last_split(author_names))
print(range(len(new_list)))

#Take each odd index value in new_list and 
def last_list(list2):
  last_name_list = []
  for x in range(len(list2)):
    if x % 2 != 0:
      last_name_list += new_list[x]
  return last_name_list

print(last_list(new_list))

1 Like

So each element NAME is split by space into individual list elements. I.e. ‘William Carlos Williams’ becomes ‘William’, ‘Carlos’, ‘Williams’. I get that part. But how is it clear that [-1] should then apply to ‘Williams’ and not the last item of the full author_names list.

Does the [-1] term reference the last variable in some temporary split list that’s been created? TIA!

This is pretty interesting! First, with the line, print(first_last_split(author_names)), you run the function one time, mutating the list, author_names. Then you run it a second time with new_list = (first_last_split(author_names)), splitting one more time. Put in a print statement to print new_list, and you’ll see this.

Then, you call += on the list. With a list, += does not behave as you expect. It works somewhat like list.extend(q), and with that method, q must be a list (Wrong! See edit.) But you are using it with a string, which, to extend the list, must be iterated over, providing the individual characters that extend the list.

empty_lst = []
empty_lst.extend('xyz')  # Using extend() with a string argument
print(empty_lst)
empty_lst += 'abc'
print(empty_lst)

# Output:
['x', 'y', 'z']
['x', 'y', 'z', 'a', 'b', 'c']

Edit: extend() takes any iterable, not just a list, as an argument.

5 Likes

Thanks. I’ll try to wrap my head around that.

Follow up question. If I rewrote it using .append how could I get the for loop to iterate over the range but then use a split on the value at that range. The code I tried to use to do that is throwing an error:

authors = "Audre Lorde, William Carlos Williams, Gabriela Mistral, Jean Toomer, An Qi, Walt Whitman, Shel Silverstein, Carmen Boullosa, Kamala Suraiyya, Langston Hughes, Adrienne Rich, Nikki Giovanni"

author_names = authors.split(',')

print(author_names)

#Split the authors names 
def first_last_split(list):
  new_list = []
  for i in list:
    new_list += i.split()
  return new_list

print(first_last_split(author_names))


def last_list(list2):
  last_name_list = []
  for [x] in range(len(list2)):
      if x % 2 != 0:
          last_name_list.append(x.split() [-1])
  return last_name_list

print(last_list(new_list))

TIA

The first error is that the variable name new_list is defined within the scope of the function first_last_split(), and is not visible in the global space, where you call print(last_list(new_list)), so you get NameError: name 'new_list' is not defined. So you should define it before that last print statement/function call like this:

new_list = first_last_split(author_names)
print(last_list(new_list))

… and then be sure to comment out the first print statement, print(first_last_split(author_names)), because that one will run the function and alter the author_names, as I mentioned earlier.

Now you get to another problem :for [x] in range(len(list2)): Why is x made into a list? omit the brackets, and you are correctly obtaining the output of range, 0, 1, 2, 3 … len(list2) -1, and assigning it to the variable x each time around the ‘for’ loop.

But, what do you do with x = 0, x = 1, etc.?? This: last_name_list.append(x.split() [-1]), where you are applying str.split() to 0, 1, 2, … This throws another error: AttributeError: 'int' object has no attribute 'split'

What you want to do is use those x’s (integers) as indexes into your list of strings.

But you seem to be still trying with if x % 2 != 0: to somehow access every other name. Even with all the above errors corrected, that approach is not going to work, thanks to William Carlos Williams, who inconveniently has three names! If you reduce the entire author’s list to individual names, then output every other one, you will be wrong by the time you get to the second author, and forever after.

How about this:
Take your initial author_names list, ['Audre Lorde', ' William Carlos Williams', ' Gabriela Mistral', ... , ' Nikki Giovanni'] , go through that list using for author in author_names: (notice: no len() or range() or index needed here!), and each time around, append() to a list author.split()[-1].

4 Likes

Help to understand please.
If we use .split() method without index[-1] we get Two-dimensional lists (arrays) :

author_names = ['Audre Lorde', 'Gabriela Mistral']

author_names_split = []
for i in author_names:
    author_names_split.append(i.split())

print(author_names_split)
#[['Audre', 'Lorde'], ['Gabriela', 'Mistral']]

But, if we use index[-1] we don’t get Two-dimensional lists (arrays), like:

>[['Lorde'], ['Mistral']]

We get list like thise:

>['Lorde', 'Mistral'] 

Why index[-1] change this?

The -1 index identifies the final element in a list.

s = “abc xyz”
s.split() gives [“abc”, “xyz”] (a list)
s.split()[-1] gives “xyz” (not a list)

4 Likes

Why is the [-1] index used after splitting the name using a space delimiter? How is the entire last name considered the -1 index? This seems like a poor example to give since there isn’t really anything relating to how to accomplish this in the lessons thus far

authors = "Audre Lorde,Gabriela Mistral,Jean Toomer,An Qi,Walt Whitman,Shel Silverstein,Carmen Boullosa,Kamala Suraiyya,Langston Hughes,Adrienne Rich,Nikki Giovanni"

author_names = authors.split(',')

print(author_names)

author_last_names = []
for name in author_names:
  author_last_names.append(name.split()[-1])
  
print(author_last_names)

this is only the case when people have a single surname, seems the exercise ignores corner cases.

3 Likes

I’m still not clear on what the [-1] index represents? Does the index represent the entire name? I thought the index would only represent a single letter within the name. In the case of -1, I figured it would be only the last letter of the name?

if you have a name:

"Audre Lorde"

and you split that, you end up with:

["Audre", "Lorde"]

and then -1 will give you the last value from the list, (-2 would give second to last item, and so forth)

so using negative indexes allow accessing a list from the right hand side.

6 Likes

ahh I was having a brain fart conflating string indexes vs list indexes. So list indexes represent the entire item in that index of the list. got it. Thank you!

2 Likes

One line: For each author name, split it by the spaces and select the last item in the resulting array:

author_last_names = [name.split(" ")[-1] for name in author_names]

e.g.
William Carlos Williams becomes [“William”, “Carlos”, “Williams”] once split.
We then select the last index using -1, which is “Williams” to get our answer.

7 Likes

My solution:

authors = "Audre Lorde, William Carlos Williams, Gabriela Mistral, Jean Toomer, An Qi, Walt Whitman, Shel Silverstein, Carmen Boullosa, Kamala Suraiyya, Langston Hughes, Adrienne Rich, Nikki Giovanni"

author_names = authors.split(",")
print(author_names)

author_last_names = []

for name in author_names:
  temp = name.split()
  author_last_names.append(temp[-1])
1 Like

EDIT - THIS CODE IS A WORKING SOLUTION WITH ONE MISTAKE, CORRECTED IN EDIT
Why am I getting an error here?

authors = "Audre Lorde, William Carlos Williams, Gabriela Mistral, Jean Toomer, An Qi, Walt Whitman, Shel Silverstein, Carmen Boullosa, Kamala Suraiyya, Langston Hughes, Adrienne Rich, Nikki Giovanni"

author_names = authors.split(",")
author_last_names = [each.split()[1] for each in author_names]

If i print(author_last_names) i get the expected print of:

[‘Lorde’, ‘Carlos’, ‘Mistral’, ‘Toomer’, ‘Qi’, ‘Whitman’, ‘Silverstein’, ‘Boullosa’, ‘Suraiyya’, ‘Hughes’, ‘Rich’, ‘Giovanni’]

but regardless I keep on getting error:

Value for author_last_names did not match the expected value

Anyone? No compilation errors…

//EDIT:
Okay found my mistake, some names have first and midle names, so instead of using index count from the front, I should count from the last.
So this line:

author_last_names = [each.split()**[1]** for each in author_names]

Has to look like this:

`author_last_names = [each.split()**[-1]** for each in author_names]`
1 Like

I did exactly this, but for me it creates a new list containing the last letter of each last name. Are you sure this worked for you?

A completely different approach to consider for extra study…

def name_split(name):
    temp = name.split()
    return {
        'first': temp.pop(0),
        'last': temp
    }

for author in author_names:
    first_last = name_split(author)
    author_first_names.append(first_last['first'])
    author_last_names.append(first_last['last'])

The name_split() method takes the first name off the list then assigns the remainder to the last name. This would work for names like,

Florence Rost van Tonningen

or,

Richard Van Dyke
4 Likes