Reputation: 63
I'm new to coding and I'm working on a question that asks to find the shortest word within a sentence. I'm confused what the difference between:
def find_short(s):
for x in s.split():
return min(len(x))
and
def find_short(s):
return min(len(x) for x in s.split())
is, because the former gives me an error and the latter seems to work fine. Are they not virtually the same thing?
Upvotes: 5
Views: 3074
Reputation: 243
Yes, the examples given are very different.
The first example effectively says:
Take the string
s
, split it by spaces, and then take each word,x
, found and return the minimum value of just the length ofx
.
The second example effectively says:
Find the minimum value in the list generated by
len(x) for x in s.split()
.
That first example generates an error because the min
function expects to compare at least 2 or more elements, and only 1 is provided.
That second example works because the list that is generated by len(x) for x in s.split()
converts a string, like say "Python types with ducks?"
to a list of word lengths (in my example, it would convert the string to [6, 5, 4, 6]
). That list that is generated (this is also why it's called a generator), is what the min
function then uses to find the minimum value inside said list.
Another way to write that first example so that it works like you would expect is like this
def find_short(s):
min_length = float("inf")
for x in s.split():
if len(x) < min_length:
min_length = len(x)
return min_length
However, notice how you have to keep track of a variable that you do not have to define using the list generator method in your second example. Although this is not a big deal when you are learning programming for the first time, it becomes a bigger deal when you start making larger, more complex programs.
Sidenote:
Any value that follows the return
keyword is what a function "outputs", and thus no more code gets executed.
For example, in your first example (and assuming that the error was not generated), your loop would only ever execute once regardless of the string you give it because it does not check that you actually have found the value you want. What I mean by that is that any time your code encounters a return
statement, it means that your function is done.
That is why in my example find_short
function, I have an if
statement to check that I have the value that I want before committing to the return
statement that exits the function entirely.
Upvotes: 1
Reputation: 386
There is mainly two mistakes here.
First of, seems you are returning the length of the string, not the string itself.
So your function will return 4 instead of 'book', for example.
I will get into how you can fix it in short.
But answering your question:
min() is a function that expects an iterable (entities like array).
In your first method, you are splitting the text, and calling return min(len(word))
for each word.
So, if the call was successfully, it would return on the first iteration.
But it is not successfully because min(3) throws an exception, 3 is not iterable.
On your second approach you are creating a list of parameters to min function.
So your code first resolves len(x) for x in s.split()
returning something like 3,2,3,4,1,3,5 as params for min, which returns the minimum value.
If you would like to return the shortest word, you could try:
def find_short(s):
y = s.split()
y.sort(key=lambda a: len(a))
return y[0]
Upvotes: 0
Reputation: 2817
No, they are not the same thing.
In first piece of code you are entering for
cycle and trying to calculate min
of the first word's length. min(5)
doesn't make sense, does it? And even if it could be calculated, return
would have stopped executing this function (other words' lengths would not have been taken into consideration).
In second one, len(x) for x in s.split()
is a generator expression yielding the lengths of all the words in your sentence. And min
will calculate the minimal element of this sequence.
Upvotes: 1
Reputation: 1283
The function min
takes an array as parameter.
On your 1st block, you have
def find_short(s):
for x in s.split():
return min(len(x))
min
is called once on the length of the 1st word, so it crashes because it's expecting an array
You second block is a little different
def find_short(s):
return min(len(x) for x in s.split())
Inside min, you have len(x) for x in s.split()
which will return an array of all the lengths and give it to min
. Then, with this array, min
will be able to return the smallest.
Upvotes: 1
Reputation: 44444
Are they not virtually the same thing?
No, they are not the same thing. If s
equals "hello world"
, in the first iteration, x
would be "hello"
. And there are two things wrong here:
min(len(x))
is like saying min(5)
which is not only an bad parameter to pass to min(..)
but also doesn't make sense. You'd want to pass a list of elements from which min
will calculate the minimum.The second approach is actually correct. See this answer of mine to get an idea of how to interpret it. In short, you are calculating length of every word, putting that into a list (actually a generator), and then asking min to run its minimum computation on it.
There's an easier approach to see why your second expression works. Try printing the result of the following:
print([len(x) for x in s.split()])
Upvotes: 3