Help understanding how the function finds the smallest number from a list

Hi all,

I need some help understanding what part of this code is doing.

#----------------------FUNCTIONS-----------------------------#

# Function to find the middle letter of a string

def middle(s):
  return s[(len(s) - 1) // 2 : len(s) // 2 + 1]
  

#----------------MAIN CODE-----------------------------------#

userStr = input('Enter your word: ')

print(middle(userStr))

So why do we need to -1 and then +1?
How does it know to return 2 letters or just one letter?

For an even string it will return both middle letters

For an uneven string it will return the middle letter

Thanks for your help.

This is the sort of thing that I think you can check by cases: check what happens when n is even, and check what happens when n is odd.

If n is even, then (n-1)/2 is not an integer, so for floor division (which is what // does), we round down to the integer (n-2)/2.

start == (n - 1)//2 == (n - 2)/2 == n/2 - 1
end == n//2 + 1 == n/2 + 1

The difference between these is 2, so the result has length 2, the two middle characters.

If n is odd, then n/2 is not an integer, so for floor division, we round down to the integer (n-1)/2.

start == (n - 1)//2 == (n - 1)/2
end == n//2 + 1 == (n - 1)/2 + 1

The difference between these is 1, so the result has length 1, just the one middle character.

That’s some clever code you show, but a little bit too clever in my opinion.

Hi thanks for the swift reply, I think i get the jist of it.

Yes my lecturer was a bit confused over this code as well :wink:

So I am right in saying that it is performing a splice on the userStr (lets call the word bucket)
and what it is trying to do is find the start and end of the splice.

return [bucket(len(bucket) - 1) // 2 = 6 -1 = 5 : first half of splice

The -1 is because the position of a list starts at 0, so the B would be position 0 and the T would be position 5. So when len counts it starts from 1 and would count up to 6 (which would give an error as position 6 on the list is empty)

5 // 2 = 2 (this is number 2 position on the list not the 2nd letter)

as you said above you use the floor division to get a whole number.

So the bucket [2: this is the starting point of the splice

The second part is the same except its + 1, I think this is because you stop at the last number not include it.

: len(bucket) // 2 + 1 ]

6 // 2 = 3 (this is the position 3 in the list not the 3rd letter)

Now we have to + 1 otherwise the splice will stop at bucket [2:3] and return only the C

so the splice will look like this bucket[2 : 4] and return the letters that are in position 2 and 3.

Hopefully that makes sense and is right i have been pondering over this for days :smiley: but i like the neatness of the code so want to be able to use it.

This is the power of mathematics :slight_smile:

def middle(s):
    return s[(len(s) - 1) // 2 : len(s) // 2 + 1]

Let’s call the length of the string N, some integer greater than zero.

(The empty string case, when N = 0, also works, but the analysis is a bit more complicated.)

If N is even (2, 4, 6, …) then N-1 is the odd number just before it, and then the floor division halves it (throwing away the remainder). If N is odd (1, 3, 5, …) then N-1 is the even number just before it, then the floor division halves it with no remainder.

So let’s do a table of values (let’s hope I get the markup right).

N    |  (N-1)//2  |  N//2
1    |      0     |   0
2    |      0     |   1
3    |      1     |   1
4    |      1     |   2
5    |      2     |   2
6    |      2     |   3
7    |      3     |   3
8    |      3     |   4

and so on. So you can see that each second and third columns advance every second row. When N is odd, the second and third columns point to the same index. When N is even, the second and third columns point to two positions exactly one place apart.

So when N is odd, the two values both point to the middle index.

When N is even, the two values point to the middle two indices.

Finally we need to add 1 to the third column (N//2 + 1) because of the way Python specifies slices. The start position is included, but the end position is not, so to include it you need to add one.

Thanks Steven that’s a great way to visualize it for me. Appreciate your time in writing explaining this code.