Finding longest word error? - python

I'm trying to find the longest word in Python but I'm getting the wrong result. The code below was done in interactive mode. I should've received 'merchandise' (10 characters) as the longest word/string but I got 'welcome' (7 characters) instead.
str = 'welcome to the merchandise store' #string of words
longest = [] #empty list
longest = str.split() #put strings into list
max(longest) #find the longest string
'welcome' #Should've been 'merchandise?'

It's sorting the strings alphabetically not by length, what you need is:
max(longest, key=len)
Let me clarify a little bit further. In Python the default comparison for strings is alphabetical. This means "aa" will be less than "abc" for all intents and purposes (cmp in python2 and < in python2/3). If you call max on the list without a key then it will compare using the default comparison. If you put in a key function then it will compare the key instead of the value. Another options (python2 only) is the cmp argument to max, which takes a function like cmp. I don't suggest this method because it's going to end up being something like cmp=lambda x,y: len(x)-len(y) which seems much less readable then just key=len and isn't supported in python3.
If you have any more questions about using key, I'd suggest reading this specifically note (7) which covers cmp and key for list.sort which uses them in the same manner.

You can also so do this:
str = 'welcome to the merchandise store'
sorted(str.split(), key=len)[-1]
Split it, sort them by length, then take the longest (last one).

Change your str.split() to str.split(" ")
Then,
max = []
for x in str.split(" "):
if len(x) > len(max[0]):
max = []
max.append(x)
elif len(x) == len(max[0]):
max.append(x)

This is one way to do it without the lambda or key=len just using a for loop and list comprehension:
str = 'welcome to the merchandise store'
longest = []
longest = str.split()
lst = []
for i in longest:
x = len(i)
lst.append(x)
y = [a for a in longest if max(lst)== len(a)]
print y[0]
Output:
merchandise
This is in Python 2, in Python 3 print (y[0])

Related

Find longest string in a list

I need to write a code where a function takes in a list and then returns the longest string from that list.
So far I have:
def longestword(alist):
a = 0
answer = ''
for i in alist:
x = i
if x > a:
a = x
answer = x
elif i == a:
if i not in alist:
answer = answer + ' ' + i
return answer
The example I have is longestword([11.22,"hello",20000,"Thanksgiving!",True])
which is supposed to return 'Thanksgiving!' but my function always returns True.
For starters, this always assigns x to the very last value in the list, which in your example is True.
for i in alist:
x = i
And you should try not to access a loop value outside of the loop because, again, it's the last value of the thing you looped over, so True
elif i == a:
The key to solving the problem is to pick out which values are strings (using isinstance()) and tracking the longest length ones (using the len() function)
def longeststring(lst):
longest = ""
for x in lst:
if isinstance(x, str) and len(x) > len(longest):
longest = x
return longest
Do be mindful of equal length strings. I don't know the requirements of your assignment.
I prefer to keep the for loops to a minimum; here's how I find the longest string in a list:
listo = ["long word 1 ", " super OMG long worrdddddddddddddddddddddd", "shortword" ]
lenList = []
for x in listo:
lenList.append(len(x))
length = max(lenList)
print("Longest string is: {} at {} characters.".format(listo[lenList.index(length)] , length))
Why not use...
str_list = [x for x in alist if isinstance(x, str)]
longestword = sorted(str_list, key=len, reverse=True)[0]
Using a list comprehension, create new_list by iterating the elements of your original list and retaining only the strings with.
And then your list will be sorted by the sorted() function.
Applying the key=len argument, your list will be sorted by the length of the list element using the built-in-function len().
And with the reverse=True argument, your list will be returned sorted in descending order, i.e. longest first.
Then you select index [0] of the sorted list which in this case, is the longest string.
To complete then:
def longestword(alist):
str_list = [x for x in alist if isinstance(x, str)]
longestword = sorted(str_list, key=len, reverse=True)[0]
return longestword
As Gavin rightly points out below, the sorting could be achieved without having to pass the reverse=True argument by returning the last element in the list with [-1], i.e.:
longestword = sorted(str_list, key=len)[-1]
You can try something like this :
def longest_string(some_list):
only_str = [s for s in some_list if isinstance(s, str)]
return max(only_str, key=len)
This method will create a list of strings named only_str. Then it will return the max length string using max() function.
When we run the longest_string() method with the example provided in the question:
some_list = [11.22,"hello",20000,"Thanksgiving!",True]
longest_string(some_list)
The output is: 'Thanksgiving!'
Hope this solves this problem!!

Finding the length of items in a Tuple (python)

I'm looking for a "for loop" that finds the length of each item and choose the largest number.
>>>T=[chicken, soda, candy]
>>>Highest = 0
>>>"for loop goes here"
>>>print (highest)
7
You need quotes around your strings (e.g. "chicken"), and the case of variables matters so Highest and highest are different. Also use round parentheses () for a tuple and square [] for a list.
A simple way to do this in Python is be to use max() to find the longest string, and len() to find the lengths, with the for keyword creating a generator expression:
T=("chicken", "soda", "candy")
Highest = max(len(x) for x in T)
print(Highest)
Slightly older versions of Python would use a list comprehension:
Highest = max([len(x) for x in T])
erip's answer showed how to use a for loop instead.
T is not a tuple, but a list. You can find out by doing print(type(T)). Try to read up on lists and Python programming in general, there are quite a few good resources available. If you want T to be a Tuple, simply change the brackets [] to regular () parenthesis like this T = ("chicken", "soda", "candy"), looping through it works the same way as mentioned below, so no need to change any of that.
The elements in your list T needs to be some kind of type or variable. What you are looking for is probably a String. To create the words as the String type, put it in double quotes like this "chicken".
Heres what I suspect that you are looking for:
T = ["chicken", "soda" ,"candy"]
Highest = 0
for word in T:
lengthOfWord = len(word)
if lengthOfWord > Highest:
Highest = lengthOfWord
print(Highest)
You can also check out a live version here.
You can create list of lengths with the following:
[len(i) for i in T]
You can then call max on an iterable, which will return the maximum element.
Putting this together you have:
print(max([len(i) for i in T]))
If you want a for-loop explicitly, you can use this:
max_length = 0
for i in T:
max_length = max(len(i), max_length))
print(max_length)
Note these both work for lists and tuples.
The question is not clear.
But I hope this will help you.
T = ('chicken', 'soda', 'candy')
Highest = 0
for i in range(0, len(T)):
if len(T[i]) > int(Highest):
Highest = len(T[i])
print ("Highest is %d" % Highest)

Find Longest Word Not Working

So I was exploring on coderbyte.com and one of the challenges is to find the longest word in a string. My code to do so is the following:
def LongestWord(sen):
current="";
currentBest=0
numberOfLettersInWord=0
longestWord=0
temp=sen.split()
for item in temp:
listOfCharacters=list(item)
for currentChar in listOfCharacters:
if currentChar.isalpha():
numberOfLettersInWord+=1
if numberOfLettersInWord>longestWord:
longestWord=numberOfLettersInWord
numberOfLettersInWord=0
currentBest=item
z = list(currentBest)
x=''
for item in z:
if item.isalpha(): x+=item
return x
testCase="a confusing /:sentence:/ this"
print LongestWord(testCase)
when testCase is "a confusing /:sentence:/"
The code returns confusing, which is the correct answer. But when the test case is the one in the current code, my code is returning 'this' instead of 'confusing'
Any ideas as to why this is happening?
I know that this is not the answer to your question, but this is how I would calculate the longest word. And not sharing it, wouldn't help you, either:
import re
def func(text: str) -> str:
words = re.findall(r"[\w]+", text)
return max(words, key=len)
print(func('a confusing /:sentence:/ this'))
Let me suggest another approach, which is more modular and more Pythonic.
Let's make a function to measure word length:
def word_length(w):
return sum(ch.isalpha() for ch in w)
So it will count (using sum()) how many characters there are for which .isalpha() is True:
>>> word_length('hello!!!')
5
>>> word_length('/:sentence:/')
8
Now, from a list of words, create a list of lengths. This is easily done with map():
>>> sen = 'a confusing /:sentence:/ this'.split()
>>> map(word_length, sen)
[1, 9, 8, 4]
Another builtin useful to find the maximum value in a list is max():
>>> max(map(word_length, sen))
9
But you want to know the word which maximizes the length, which in mathematical terms is called argument of the maximum.
To solve this, zip() the lengths with the words, and get the second argument found by max().
Since this is useful in many cases, make it a function:
def arg_max(func, values):
return max(zip(map(func, values), values))[1]
Now the longest word is easily found with:
>>> arg_max(word_length, sen)
'confusing'
Note: PEP-0008 (Style Guide for Python Code) suggests that function names be lower case and with words separated by underscore.
You loop through the words composing the sentence. However, numberOfLettersInWord is never reseted so it keeps increasing while you iterate among the words.
You have to set the counter to 0 each time you start a new word.
for item in temp:
numberOfLettersInWord = 0
It solves your issue as you can see: https://ideone.com/y1cmHX
Here's a little function I just wrote that will return the longest word, using a regular expression to remove non alpha-numeric characters
import re
def longest_word(input):
words = input.split()
longest = ''
for word in words:
word = re.sub(r'\W+', '', word)
if len(word) > len(longest):
longest = word
return longest
print(longest_word("a confusing /:sentence:/ this"))

How to alphabetically sort a text file in python without sort function?

I have to alphabetically sort a text file where each new word is on a new line. I currently have the whitespace stripped and my program prints the first letter attaching it to a integer with the ord function. I cannot use sort and I know I have to put it into a list just not sure how. This is what i wrote for the lists.
lists = [ [] for _ in range( 26 ) ]
If you can't use the sort() method, the sorted() function is your next bet.
words = [...]
sorted_words = sorted(words)
Unlike words.sort(), using sorted() won't modify its input, and it works on arbitrary iterables.
You could use the following function to sort your list of words:
def qsort(array):
if len(array) < 2:
return array
head, *tail = array
less = qsort([item for item in tail if item < head])
more = qsort([item for item in tail if item >= head])
return less + [head] + more
For the range command you have to put two exclusive integers as parameters for example range(0,11) will pick a number between 1 and 10. This is probably why you can use range(). Also you need to use a column to follow range():.

HOW TO "Arbitrary" format items in list/dict/etc. EX: change 4th character in every string in list

first of all i want to mention that there might not be any real life applications for this simple script i created, but i did it because I'm learning and I couldn't find anything similar here in SO. I wanted to know what could be done to "arbitrarily" change characters in an iterable like a list.
Sure tile() is a handy tool I learned relatively quick, but then I got to think what if, just for kicks, i wanted to format (upper case) the last character instead? or the third, the middle one,etc. What about lower case? Replacing specific characters with others?
Like I said this is surely not perfect but could give away some food for thought to other noobs like myself. Plus I think this can be modified in hundreds of ways to achieve all kinds of different formatting.
How about helping me improve what I just did? how about making it more lean and mean? checking for style, methods, efficiency, etc...
Here it goes:
words = ['house', 'flower', 'tree'] #string list
counter = 0 #counter to iterate over the items in list
chars = 4 #character position in string (0,1,2...)
for counter in range (0,len(words)):
while counter < len(words):
z = list(words[counter]) # z is a temp list created to slice words
if len(z) > chars: # to compare char position and z length
upper = [k.upper() for k in z[chars]] # string formatting EX: uppercase
z[chars] = upper [0] # replace formatted character with original
words[counter] = ("".join(z)) # convert and replace temp list back into original word str list
counter +=1
else:
break
print (words)
['housE', 'flowEr', 'tree']
This is somewhat of a combination of both (so +1 to both of them :) ). The main function accepts a list, an arbitrary function and the character to act on:
In [47]: def RandomAlter(l, func, char):
return [''.join([func(w[x]) if x == char else w[x] for x in xrange(len(w))]) for w in l]
....:
In [48]: RandomAlter(words, str.upper, 4)
Out[48]: ['housE', 'flowEr', 'tree']
In [49]: RandomAlter([str.upper(w) for w in words], str.lower, 2)
Out[49]: ['HOuSE', 'FLoWER', 'TReE']
In [50]: RandomAlter(words, lambda x: '_', 4)
Out[50]: ['hous_', 'flow_r', 'tree']
The function RandomAlter can be rewritten as this, which may make it a bit more clear (it takes advantage of a feature called list comprehensions to reduce the lines of code needed).
def RandomAlter(l, func, char):
# For each word in our list
main_list = []
for w in l:
# Create a container that is going to hold our new 'word'
new_word = []
# Iterate over a range that is equal to the number of chars in the word
# xrange is a more memory efficient 'range' - same behavior
for x in xrange(len(w)):
# If the current position is the character we want to modify
if x == char:
# Apply the function to the character and append to our 'word'
# This is a cool Python feature - you can pass around functions
# just like any other variable
new_word.append(func(w[x]))
else:
# Just append the normal letter
new_word.append(w[x])
# Now we append the 'word' to our main_list. However since the 'word' is
# a list of letters, we need to 'join' them together to form a string
main_list.append(''.join(new_word))
# Now just return the main_list, which will be a list of altered words
return main_list
There's much better Pythonistas than me, but here's one attempt:
[''.join(
[a[x].upper() if x == chars else a[x]
for x in xrange(0,len(a))]
)
for a in words]
Also, we're talking about the programmer's 4th, right? What everyone else calls 5th, yes?
Some comments on your code:
for counter in range (0,len(words)):
while counter < len(words):
This won't compile unless you indent the while loop under the for loop. And, if you do that, the inner loop will completely screw up the loop counter for the outer loop. And finally, you almost never want to maintain an explicit loop counter in Python. You probably want this:
for counter, word in enumerate(words):
Next:
z = list(words[counter]) # z is a temp list created to slice words
You can already slice strings, in exactly the same way you slice lists, so this is unnecessary.
Next:
upper = [k.upper() for k in z[chars]] # string formatting EX: uppercase
This is a bad name for the variable, since there's a function with the exact same name—which you're calling on the same line.
Meanwhile, the way you defined things, z[chars] is a character, a copy of words[4]. You can iterate over a single character in Python, because each character is itself a string. but it's generally pointless—[k.upper() for k in z[chars]] is the same thing as [z[chars].upper()].
z[chars] = upper [0] # replace formatted character with original
So you only wanted the list of 1 character to get the first character out of it… why make it a list in the first place? Just replace the last two lines with z[chars] = z[chars].upper().
else:
break
This is going to stop on the first string shorter than length 4, rather than just skip strings shorter than length 4, which is what it seems like you want. The way to say that is continue, not break. Or, better, just fall off the end of the list. In some cases, it's hard to write things without a continue, but in this case, it's easy—it's already at the end of the loop, and in fact it's inside an else: that has nothing else in it, so just remove both lines.
It's hard to tell with upper that your loops are wrong, because if you accidentally call upper twice, it looks the same as if you called it once. Change the upper to chr(ord(k)+1), which replaces any letter with the next letter. Then try it with:
words = ['house', 'flower', 'tree', 'a', 'abcdefgh']
You'll notice that, e.g., you get 'flowgr' instead of 'flowfr'.
You may also want to add a variable that counts up the number of times you run through the inner loop. It should only be len(words) times, but it's actually len(words) * len(words) if you have no short words, or len(words) * len(<up to the first short word>) if you have any. You're making the computer do a whole lot of extra work—if you have 1000 words, it has to do 1000000 loops instead of 1000. In technical terms, your algorithm is O(N^2), even though it only needs to be O(N).
Putting it all together:
words = ['house', 'flower', 'tree', 'a', 'abcdefgh'] #string list
chars = 4 #character position in string (0,1,2...)
for counter, word in enumerate(words):
if len(word) > chars: # to compare char position and z length
z = list(word)
z[chars] = chr(ord(z[chars]+1) # replace character with next character
words[counter] = "".join(z) # convert and replace temp list back into original word str list
print (words)
That does the same thing as your original code (except using "next character" instead of "uppercase character"), without the bugs, with much less work for the computer, and much easier to read.
I think the general case of what you're talking about is a method that, given a string and an index, returns that string, with the indexed character transformed according to some rule.
def transform_string(strng, index, transform):
lst = list(strng)
if index < len(lst):
lst[index] = transform(lst[index])
return ''.join(lst)
words = ['house', 'flower', 'tree']
output = [transform_string(word, 4, str.upper) for word in words]
To make it even more abstract, you could have a factory that returns a method, like so:
def transformation_factory(index, transform):
def inner(word):
lst = list(word)
if index < len(lst):
lst[index] = transform(lst[index])
return inner
transform = transformation_factory(4, lambda x: x.upper())
output = map(transform, words)

Categories