Higher order function in Python exercise - python

I learning Python and during solution an exercise, function filter() returns empty list and i can't understand why. Here is my source code:
"""
Using the higher order function filter(), define a function filter_long_words()
that takes a list of words and an integer n and returns
the list of words that are longer than n.
"""
def filter_long_words(input_list, n):
print 'n = ', n
lengths = map(len, input_list)
print 'lengths = ', lengths
dictionary = dict(zip(lengths, input_list))
filtered_lengths = filter(lambda x: x > n, lengths) #i think error is here
print 'filtered_lengths = ', filtered_lengths
print 'dict = ',dictionary
result = [dictionary[i] for i in filtered_lengths]
return result
input_string = raw_input("Enter a list of words\n")
input_list = []
input_list = input_string.split(' ')
n = raw_input("Display words, that longer than...\n")
print filter_long_words(input_list, n)

Your function filter_long_words works fine, but the error stems from the fact that when you do:
n = raw_input("Display words, that longer than...\n")
print filter_long_words(input_list, n)
n is a string, not an integer.
Unfortunately, a string is always "greater" than an integer in Python (but you shouldn't compare them anyway!):
>>> 2 > '0'
False
If you're curious why, this question has the answer: How does Python compare string and int?
Regarding the rest of your code, you should not create a dictionary that maps the lengths of the strings to the strings themselves.
What happens when you have two strings of equal length? You should map the other way around: strings to their length.
But better yet: you don't even need to create a dictionary:
filtered_words = filter(lambda: len(word) > n, words)

n is a string. Convert it to an int before using it:
n = int(raw_input("Display words, that longer than...\n"))
Python 2.x will attempt to produce a consistent-but-arbitrary ordering for objects with no meaningful ordering relationship to make sorting easier. This was deemed a mistake and changed in the backwards-incompatible 3.x releases; in 3.x, this would have raised a TypeError.

I don't know what your function does, or what you think it does, just looking at it gives me a headache.
Here's a correct answer to your exercise:
def filter_long_words(input_list, n):
return filter(lambda s: len(s) > n, input_list)

My answer:
def filter_long_words():
a = raw_input("Please give a list of word's and a number: ").split()
print "You word's without your Number...", filter(lambda x: x != a, a)[:-1]
filter_long_words()

Related

how to convert a string of numbers to a list and square up ** and get it printed out back as string

Given a string of the form "3,9,13,4,42". It is necessary to convert it into a list and calculate its square for each element. Then join the squares of those elements back into a string and print it in the console.
input
input:
string = "3,9,13,4,42"
output:
string= "9,81,169,16,1764"
Managed to get it squared up, tried converting it to list fist, but when checked type at the end, always somehow getting it as tuple.
Ty for help.
Hope this answers your question.
# input
str_numbers = "3,9,13,4,42"
# string to list
str_number_list = str_numbers.split(",")
# list of strings to list of ints
number_list = [int(x) for x in str_number_list]
# square all numbers
squared_numbers = [x ** 2 for x in number_list]
# squared numbers back to a list of strings
str_squared_numbers = [str(x) for x in squared_numbers]
# joing the list items into one string
result = ",".join(str_squared_numbers)
# print it out
print(f"Input: {str_numbers}")
print(f"Output: {result}")
// First Approach
string = "3,9,13,4,42"
array = string.split(',')
array = map(lambda x: str(int(x)**2),array)
result = ','.join(list(array))
print(result) // "9,81,169,16,1764"
// Second Approach
string = "3,9,13,4,42"
result = ','.join([str(int(x)**2) for x in string.split(',')])
print(result) // '9,81,169,16,1764'
Can do with split + join,
In [1]: ','.join(map(lambda x: str(int(x)**2), s.split(',')))
Out[1]: '9,81,169,16,1764'
You have so many ways to solve the problem. I'll show you a few by degree of complexity of understanding. Each way has a different computational complexity, but for such a problem we will not go into detail.
N.B.: Casting should be done at float and not at int because it is not certain a priori that there are integers in the input string.
Using List Comprehension
List comprehension offers a shorter syntax when you want to create a
new list based on the values of an existing list.
I divide the code into 3 steps just for greater understanding:
input_string = "3,9,13,4,42"
num_list = [float(x) for x in input_string.split(",")] # split list by comma and cast each element to float
squares_list = [x**2 for x in num_list] # make square of each number in list
output_string = [str(x) for x in squares_list] # cast to string each element in list
print(output_string)
Using join, map and lambda
The join() method takes all items in an iterable and joins them into
one string.
The map() function applies a given function to each item of an
iterable (list, tuple etc.) and returns an iterator.
A Lambda Function is an anonymous function, that is, a function that
has not been assigned a name and is used to use the features of
functions but without having to define them.
output_string = ','.join(map(lambda x: str(float(x)**2), input_string.split(',')))
You are absolutely right assume-irrational-is-rational
string = "3,9,13,4,42"
def squares_string(string):
output = ",".join(tuple(map(lambda x: str(int(x)**2), "3,9,13,4,42".split(","))))
return output
output = squares_string(string)
print(output)
print(type(output))
Result:
9,81,169,16,1764
<class 'str'>

How do I check if the next item in a string is the alphabetical successor of the one before? + Inverse

I'm trying to compress a string in a way that any sequence of letters in strict alphabetical order is swapped with the first letter plus the length of the sequence.
For example, the string "abcdefxylmno", would become: "a6xyl4"
Single letters that aren't in order with the one before or after just stay the way they are.
How do I check that two letters are successors (a,b) and not simply in alphabetical order (a,c)? And how do I keep iterating on the string until I find a letter that doesn't meet this requirement?
I'm also trying to do this in a way that makes it easier to write an inverse function (that given the result string gives me back the original one).
EDIT :
I've managed to get the function working, thanks to your suggestion of using the alphabet string as comparison; now I'm very much stuck on the inverse function: given "a6xyl4" expand it back into "abcdefxylmno".
After quite some time I managed to split the string every time there's a number and I made a function that expands a 2 char string, but it fails to work when I use it on a longer string:
from string import ascii_lowercase as abc
def subString(start,n):
L=[]
ind = abc.index(start)
newAbc = abc[ind:]
for i in range(len(newAbc)):
while i < n:
L.append(newAbc[i])
i+=1
res = ''.join(L)
return res
def unpack(S):
for i in range(len(S)-1):
if S[i] in abc and S[i+1] not in abc:
lett = str(S[i])
num = int(S[i+1])
return subString(lett,num)
def separate(S):
lst = []
for i in S:
lst.append(i)
for el in lst:
if el.isnumeric():
ind = lst.index(el)
lst.insert(ind+1,"-")
a = ''.join(lst)
L = a.split("-")
if S[-1].isnumeric():
L.remove(L[-1])
return L
else:
return L
def inverse(S):
L = separate(S)
for i in L:
return unpack(i)
Each of these functions work singularly, but inverse(S) doesn't output anything. What's the mistake?
You can use the ord() function which returns an integer representing the Unicode character. Sequential letters in alphabetical order differ by 1. Thus said you can implement a simple funtion:
def is_successor(a,b):
# check for marginal cases if we dont ensure
# input restriction somewhere else
if ord(a) not in range(ord('a'), ord('z')) and ord(a) not in range(ord('A'),ord('Z')):
return False
if ord(b) not in range(ord('a'), ord('z')) and ord(b) not in range(ord('A'),ord('Z')):
return False
# returns true if they are sequential
return ((ord(b) - ord(a)) == 1)
You can use chr(int) method for your reversing stage as it returns a string representing a character whose Unicode code point is an integer given as argument.
This builds on the idea that acceptable subsequences will be substrings of the ABC:
from string import ascii_lowercase as abc # 'abcdefg...'
text = 'abcdefxylmno'
stack = []
cache = ''
# collect subsequences
for char in text:
if cache + char in abc:
cache += char
else:
stack.append(cache)
cache = char
# if present, append the last sequence
if cache:
stack.append(cache)
# stack is now ['abcdef', 'xy', 'lmno']
# Build the final string 'a6x2l4'
result = ''.join(f'{s[0]}{len(s)}' if len(s) > 1 else s for s in stack)

Python - Function to reverse strings in LIST

studying Python as crazy and have many many questions.
This time about function, i need to create 2 functions, first for numbers to sum up everything that user inputs in the list and second function, where user inputs some words in to the list and function without touching word indexes in the list, takes each word and returns reversed words (On the same index)
I can show you my code, i think i don't have problems with numbers and its function, i need your help with reverse function, i tried some ways, even one "for" in another, but i prefer some easy ways.
def sum(numbers):
acc = 0
for numb in numbers:
acc += numb
return acc
def rever(strings):
r = []
for i in strings:
for n in i:
reversed(r[n])
return r
numbers = [int(x) for x in input("Please input at least 5 numbers (Use space): ").split()]
print(sum(numbers))
strings = [str(x) for x in input("Please input at least 5 words (Use Space): ").split()]
print(rever(strings))
For your first function, that already exists as a built-in function of same name (sum()). For the second, you can use a simple list comprehension.
def rever(strings):
return [x[::-1] for x in strings]
Judging by your question it seems you are learning functions in python, you can reverse the list using a function like this:
strings_ = [str(x) for x in input("Please input at least 5 words (Use Space): ").split()]
for index,item in enumerate(strings_):
def recursion_reverse(string_1):
if not string_1:
return ""
else:
front_part=recursion_reverse(string_1[1:])
back_part=string_1[0]
return front_part+back_part[0]
strings_[index]=recursion_reverse(item)
print(strings_)
output:
Please input at least 5 words (Use Space): Hello world this is me
['olleH', 'dlrow', 'siht', 'si', 'em']

Implementing a function that sums integers contained in a string in Python

So I've recently picked up John Guttag's Introduction to Computation and Programming Using Python,the revised and expanded edition, after having worked through most of LPTHW. I am using the book in conjunction with MIT OCW 006. Now, I was trying to complete one of the Finger Exercises listed in the book, specifically the one of page 85, chapter 7, where the author asks you to implement a function using a try-except block:
def sumDigits(s):
"""Assumes s is a string
Returns the sum of the decimal digits in s
For example, if is is'a2b3c' it returns 5"""
This is my code:
def sumDigits(s):
try:
total = 0
list1 = [s]
new_list = [x for x in list1 if x.isdigit()]
for e in new_list:
total += new_list[e]
return total
except TypeError:
print "What you entered is not a string."
When I run this program in the IDLE using a test input, the total is always computed to be zero, indicating that none of the elements of new_list are being passed to the accumulator. Could someone suggest why that is? Thanks.
It seems like the errors have been pointed out already by Rafael but it is still important to note that the more pythonic way to approach this would be:
return sum([int(x) for x in s if x.isdigit()])
There are actually several errors with your code.
Let's break them down in detail
The main problem is located in these lines:
list1 = [s]
new_list = [x for x in list1 if x.isdigit()]
You should loop directly over the string first
new_list = [x for x in s if x.isdigit()] #s is the input string
When you create a new list as you did, the variable x in x for x in list1 will take place as elements of the list. So, in your case, the list will have only one element, which happen to be whole string (because you defined the list as [s]. As the whole string is not a digit, new_list will be an empty list.
That is why you are getting 0 as a return.
However, if you loop through the string directly, x will take place as each letter in the string, and then it will be possible to check whether x is digit or not.
It is also important to highlight that new_list[e] will raise IndexError. You should correct that for e only. The sintax of for e in new_list makes the local variable e assume each value inside the list, so you do not have to get the value via indexes: you can use e directly.
Finally, in order to sum the values in your new_list, the values should be integers (int) and not string (str), so you have to cast the values to int before summing (or, you can cast each element to int during the list comprehension, by using int(x) for x in s if x.isdigit() instead of x for x in s if x.isdigit()). Also, in order to check if the input is a string or not, you better use isinstance(s, basestring) if you're in python2, or isinstance(s, str) if you're using python3.
So the whole code would look like this :
def sumDigits(s):
if isinstance(s, basestring):
total = 0
new_list = [x for x in s if x.isdigit()]
for e in new_list:
total += int(e)
return total
else:
print "What you entered is not a string."
I'm working through the same book and the MITx: 6.00.1x course on edX; here's my solution:
def sumDigits(s):
'''
Assumes s is a string
Returns the sum of the decimal digits in s
For example, if s is 'a2b3c' it returns 5
'''
result = 0
try:
for i in range(len(s)):
if s[i].isdigit():
result += int(s[i])
return result
except:
print('Your input is not a string.')
Since we are to assume that s is a string, the except block should handle those cases where s is not a string. So simple, but it was not obvious to me at first.
You can use reduce method
reduce( (lambda x, y: x + y), [int(x) for x in new if x.isdigit()] )
I'm working through the same book too. I think we should use the try-except block on determining whether characters of string convertible to an integer. So here is my solution.
def sumDigits(s):
"""Assumes s is a string
Returns the sum of the decimal digits in s
For example, if s is 'a2b3c' it returns 5"""
sum = 0
for i in s:
try:
sum += int(i)
except ValueError:
None
return sum

Comparing string differences to a list of strings

I have a method, that computes the number of differences in two strings, and outputs where the differences are.
def method(a):
count=0
s1="ABC"
for i in range (len(a)):
if not a[i]==s1[i]:
count=count+1
else:
count=count+0
return a,count,difference(a, s1)
On input ex CBB, this method outputs
('CBB', 2, [1, 0, 1])
What I really need is for this method to do the same, but where is not only compares to a single string in s1, but to a list of strings
s1 = ['ACB', 'ABC', 'ABB']
Anyone with a smart method to do this?
Ok, after clarification, instead of hardcoding s1, make your method take it as argument:
def method(a, s1):
count=0
for i in range (len(a)):
if not a[i]==s1[i]:
count=count+1
else:
count=count+0
return a,count,difference(a, s1)
Then use list compherension:
result = [method(a, s1) for s1 in list]
Be careful though, as your method will fail if a is longer than s1. As you really don't say what the result should be in that case, i left it as is.
the compare function calculates the number of differences (and map of differences that you had been creating with difference()). I rewrote the compare function to take a base string to be compared to, src, so that you don't get stuck with comparing to "ABC" all the time.
def compare(src, test):
if len(src) != len(test):
return # must be the same length
diffmap = [0]*len(src)
count = 0
for i, c in enumerate(src):
if not c == test[i]:
count = count+1
diffmap[i] = 1
return test, count, diffmap
The compare_to_many function simply goes through a list of strings to compare to, srcs, and creates a list of the comparisons between those base strings and a test string test.
def compare_to_many(srcs, test):
return map(lambda x: compare(x, test), srcs)
EDIT:
After clarification in the comments, #X-Pender needs the source list to be hardcoded. This can be reflected by the following, single function:
def compare(test):
def compare_one(src, test):
diffmap = [0]*len(src)
count = 0
for i, c in enumerate(src):
if not c == test[i]:
count = count+1
diffmap[i] = 1
return test, count, diffmap
sources = ["ABC", "CDB", "EUA"] # this is your hardcoded list
return map(lambda x: compare_one(x, test), sources)

Categories

Resources