6
\$\begingroup\$

I am writing a function where I can take a string as input, and then find the even number of substrings. The final result is the first longest even length string is returned by the function.

For example:

Input -> It is a pleasant day today

Output -> pleasant

For example:

Input -> It is a day today

Output-> It

(Since there are two sub-strings of the same even length, returning the first longest even length string is enough.)

If there are no such even length strings then, the function should return 00.

import sys


def longestEvenWord(sentence):
    list1 = sentence.split()

    for x in list1[:]:
        # just removing all the odd length words from
        # the list. Then the list will contain only
        # even words
        if (len(x) % 2 != 0):
            list1.remove(x)
    #after removing the odd length numbers, we will have only even and find the
    #longest word and return that.
    return max(list1, key=len)


if __name__ == '__main__':
    result = longestEvenWord(" qqqqqqqqq It is a day today qqqqqqqqq")
    print(result)
\$\endgroup\$
0

4 Answers 4

3
\$\begingroup\$

Firstly, "sub-string" is different than "word". I think "word" is more appropriate in this situation. (A substring can contain non-alphabetical characters).

import sys

You never use this. Get rid of it.

list1 = sentence.split()

This assignment is not terribly necessary.

Your algorithm can be simplified considerably. I think this should be left as an exercise, but here are some things you shouldn't have to do in the new algorithm:

  1. Don't make a copy of the list.
  2. Have some sort of best variable and best_count integer that stores the longest even word found and the length of that word.
  3. After looping through the sentnce, return best.

Using this algorithm you only hit each word once instead of going through the even words again as you do in your algorithm.

The PEP8 style guide states that Python functions use snake_case instead of camelCase so: longestEvenWord -> longest_even_word.

\$\endgroup\$
1
  • \$\begingroup\$ Could Jamal please explain me why the second piece of code is deleted? \$\endgroup\$
    – hago
    Jul 30, 2017 at 21:07
2
\$\begingroup\$

Nice solution. Only one improvement:

Instead of building a list and then remove items from it

list1 = sentence.split()

for x in list1[:]:
    # just removing all the odd length words from
    # the list. Then the list will contain only
    # even words
    if (len(x) % 2 != 0):
        list1.remove(x)

it is possible to use

list1 = [word for word in sentence.split() if len(word) % 2 == 0 ]
\$\endgroup\$
3
  • \$\begingroup\$ Hi Marian, I actually did a similar solution but I see that another moderator has deleted it.. \$\endgroup\$
    – hago
    Jul 30, 2017 at 21:09
  • \$\begingroup\$ @hago - So he will probably delete the mine, too :-) \$\endgroup\$
    – MarianD
    Jul 30, 2017 at 21:13
  • \$\begingroup\$ The other "answer" didn't review the code (it was just a code block of a different implementation without any critique of the question code, or any explanation of what was better about the proposal). This one does seem to be an actual review, so it hasn't been nominated for deletion. \$\endgroup\$ Sep 4 at 7:23
1
\$\begingroup\$

If you keep track of the length of the longest item, you can save a call to max()

longest = ""
for word in (w for w in sentence.split(" ") if len(w) % 2 == 0 and len(w) > len(longest)):
    longest = word
\$\endgroup\$
1
\$\begingroup\$

Since you say the input string could be "large", it's probably unwise to try to store the words in a list like this:

list1 = sentence.split()

Instead, read the answers to Is there a generator version of string.split() in Python? and pick one you like. For example, I'd like to be able to handle input from a stream if it's too big to fit in memory, so I chose this one:

import itertools

def iter_split(string, sep=' '):
    groups = itertools.groupby(string, lambda s: s != sep)
    return (''.join(g) for k, g in groups if k)

The odd-length words can be removed by filtering as a generator expression (similar to MarianD's answer, but as a generator expression):

gen = (word for word in iter_split(input) if len(word) % 2 == 0)

The max() function makes a single pass over its iterable input, so needs no change to work with a generator:

return max(gen, key=len)

You could choose to combine the filtering with the max key-function instead:

return max(iter_split(input), lambda s: len(s) if len(s) % 2 == 0 else None)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.