I am learning python and was going through my tutorial. I came across this code segment and want to know if it can be replaced using a simple loop without using inbuilt .join()
return choice("".join(x * y for x, y in items))
Can someone help me with this?
You can:
value = ''
for x, y in items:
value += x * y
return choice(value)
but know that this will be slower as you now have to build a new string value for each and every iteration over items. The ''.join() only has to build one new string object.
If choice() is random.choice(), x is a string and y an integer, and this is a weighted random choice function, you should also be able to use a list:
value = []
for x, y in items:
value += list(x) * y
return choice(value)
Related
I'm kinda new to Programming and Python and I'm self learning before going to uni so please be gentle, I'm a newbie. I hope my english won't have too many grammatical errors.
Basically I had this exercise in a book I'm currently reading to take a list of tuples as a function parameter, then take every item in the each tuple and put it to 2nd power and sum the items up.
My code looks like this and works good if my function call includes the same amount of arguments as the function for loop requires:
def summary(xs):
for x,y,z in xs:
print( x*x + y*y + z*z)
xs =[(2,3,4), (2,-3,4), (1,2,3)]
summary(xs)
However, If I use a list with less tuples than the function definition, I get an error: ValueError : not enough values to unpack(expected 3, got 0):
xs =[(2,3,4), (), (1,2,3)]
I would like to know how to make a function that would accept a tuple I shown before () - with no tuples, and the function would return 0. I have been trying multiple ways how to solve this for 2 days already and googling as well, but it occurs to me I'm either missing something or I'm not aware of a function i could use. Thank you all for the help.
One way is to iterate over the tuple values, this would also be the way to tackle this problem in nearly every programming language:
def summary(xs):
for item in xs:
s = 0
for value in item:
s += value**2
print(s)
Or using a list comprehension:
def summary(xs):
for item in xs:
result = sum([x**2 for x in item])
print(result)
also note that sum([]) will return 0 for an empty iterable.
Well, the issue is that you don't have enough indices in your inner tuple to unpack into three variables. The simplest way to go around it is to manually unpack after checking that you have enough variables, i.e.:
def summary(xs):
for values in xs:
if values and len(values) == 3:
x, y, z = values # or don't unpack, refer to them by index, i.e. v[0], v[1]...
print(x*x + y*y + z*z)
else:
print(0)
Or use a try..except block:
def summary(xs):
for values in xs:
try:
x, y, z = values # or don't unpack, refer to them by index, i.e. v[0], v[1]...
print(x*x + y*y + z*z)
except ValueError: # check for IndexError if not unpacking
print(0)
One way is to use try / except. In the below example, we use a generator and catch occasions when unpacking fails with ValueError and yield 0.
While you are learning, I highly recommend you practice writing functions which return or yield rather than using them to print values.
def summary(xs):
for item in xs:
try:
yield sum(i**2 for i in item)
except ValueError:
yield 0
xs = [(2,3,4), (), (1,2,3)]
res = list(summary(xs))
print(res)
[29, 0, 14]
Or to actually utilise the generator in a lazy fashion:
for i in summary(xs):
print(i)
29
0
14
You should use the "len > 0" condition. This code should work for any list or tuple length :
def summary(xs):
for tup in xs:
prod = [a*a for a in tup if len(tup)>0]
print(sum(prod))
Note that I defined a "prod" list in order to use "sum" so that it is not calculated the hard way. It replaces your "x* x + y* y + z* z" and works for any tuple length.
It often pays to separate your algorithm into functions that just do one thing. In this case a function to sum the squares of a list of values and a function to print them. It is very helpful to keep your variable names meaningful. In this case your xs is a list of lists, so might be better named xss
import math
def sum_of_squares(xs):
return sum(map(math.sqr, xs))
def summary(xss):
for xs in xss:
print sum_of_squares(xs)
xss = [(2,3,4), (), (1,2,3)]
summary(xss)
or
map(print, sum(map(math.sqr, (x for x in xs))))
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
I'm relatively new to computer science, and I'm learning how to code in python. I'm trying to figure out how to make a function that takes a list and returns a list of suffixes from the inputted list, in order from shortest length to longest length. For example, entering
[3,4,2,-9,7,6,1]
to the function would return
[[],[1],[6,1],[7,6,1],[-9,7,6,1],[2,-9,7,6,1],[4,2,-9,7,6,1],[3,4,2,-9,7,6,1]]
I've tried several approaches, but so far I'm not having much luck. Here is what I have so far:
def h(m):
newlist = []
x = 0
y = (len[m])-1
while x in range(y):
sublist = []
sublist = sublist + m[x:y]
newlist.append(sublist)
x += 1
return new list
When I try to run the function by entering something like
a = [3,4,2,-9,7,6,1]
h(a)
I get an error:
Traceback (most recent call last):
File "<pyshell#239>", line 1, in <module>
h(a)
File "<pyshell#238>", line 4, in h
y = (len[m])-1
TypeError: 'builtin_function_or_method' object has no attribute '__getitem__'
My objective with this bit of code was simply to create a the list of suffixes without sorting them by length. After I figure out how to create this new list I will add the sorting bit of the code. Keep in mind this is not a homework assignment. Any help would be greatly appreciated!
Possible solution is using list comprehension:
[l[i:] for i in range(len(l), -1, -1)]
This code uses slicing and list comprehension to simply return a list of slices from the end. Using your code, small modification is required - len is a function and not a dictionary, therefore you need to use the call operator () instead of subscript operator [].
y = len(m) - 1
That will not yield correct result though, because you will not get the last suffix and empty suffix. In order to cover these two, you will need to modify y or the loop to cover them
y = len(m) + 1
or better
while x in range(y + 1):
use parenthesis to get the length of the list:
y = len(m) - 1
Your error is in your len:
(len[m]) - 1
len is a function, and you can't index or slice or the what not. Do this instead:
y = len(m) - 1
There's also one other error:
return new list
Should be: (You can't have spaces in variables)
return newlist
from random import *
def f(one):
x=randrange(0,len(one))
y=randrange(0,len(one))
return(one)
print(one(["20","40","60"]))
the function is supposed to take an input parameter a list of strings and generates two random numbers between 0 and the length of the list but how do you return the list with the slice between the two numbers removed.
First you are not calling the function you've created, you must:
print( f(["20","40","60"]) )
Second, your function f() is not doing anything, is just creating two variables x and y but returning the same list it received as parameter.
And to return the sliced list:
from random import *
def f(one):
x=randrange(0,len(one))
y=randrange(0,len(one))
print (x, y)
return one[x:y]
print(f(["20","40","60"]))
Remember that randrange(x, y) returns a value between x and y - 1
The sublist of a list one from index i up to (but not including!) index j is written in Python as one[i:j]. I think you can figure out the rest from here.
Full disclosure: this is for an assignment. Simply getting working code is enough, but doing this in three lines gets me extra credit.
I'm trying to take a 1000-digit string and find the largest product of 5 consecutive digits. You may recognize this as Project Euler's Problem #8.
I've tried a lot of options, but I seem to be stuck. I'm working on figuring out if I can make a lambda statement that will work, but I have no experience with lambda so it's evading me.
Here's what I have so far:
for i in range(1, 996):
max = int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) if max < int(number[i+0]) * int(number[i+1]) * int(number[i+2]) * int(number[i+3]) * int(number[i+4]) else max = max
return max
That doesn't work and triggers SyntaxError: can't assign to conditional expression.
I don't want outright code, or at least not a complete function, but just a little help understanding how I can move forward.
This isn't legal python:
x = y if z else x = w
This is:
x = y if z else w
So is this:
if z: x = y
By the way, there is a one line solution, that is much shorter and clearer than your three.
= appears twice in your (very long) line. Effectively you have this:
max = something if something else max = max
which Python parses as:
max = (something if something else max) = max
And, indeed, you can't assign to a conditional expression, which is that whole thing in the middle.
You probably didn't intend to have the final = max at the end.
In [15]: def myinput(l,n):
...: for x in l:
...: yield l[x:x+n]
...:
In [16]: max([reduce(lambda a,b:a*b, x) for x in myinput(range(1000),5) if len(x)==5])
Out[16]: 985084775273880L
Like recursive mentioned, there is a simple one-liner solution. It involves using the max function - always bad to name variables after builtins!
In Python 2 it looks something like this:
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in xrange(996))
In Python 3 reduce was removed, so you have to get it through functools:
from functools import reduce
max(reduce(lambda x, y: x*y, map(int, num[i:i+5])) for i in range(996))
Look into:
the built-in max function to find the greatest number in a sequence,
the built-in map function to apply a function to all elements in a list,
the built-in reduce function to obtain a single object as a result of applying a function that returns a single object repeatedly to two elements in a list,
lambda definitions to be able to define function objects that you can pass to map() and reduce(),
and list comprehensions (and generators, which are very similar) to compose the above functions in a one-liner.