I am starting to learn how to use python in a functional way and I am facing a problem I can't solve.
I have the following code (take in part from this question) which does exactly what I want:
url = "www.testpage.com/"
def gen_url(prefix, suffix, places=3):
pattern = "{}{{:0{}d}}{}".format(prefix, places, suffix)
for i in count(1):
yield pattern.format(i)
list_of_urls = []
for c in "xyz":
g = gen_url(url+c,"&show=more")
for x in range(2):
list_of_urls.append(next(g))
And it generates something like this:
www.testpage.com/x001&show=more
www.testpage.com/y001&show=more
www.testpage.com/z001&show=more
www.testpage.com/x002&show=more
www.testpage.com/y002&show=more
www.testpage.com/z002&show=more
As you can see, It stops at 002 because of:
...
for x in range(2):
list_of_urls.append(next(g))
...
All the time I start with an empy list, use a for loop and fill it. I am trying to use map in this way and get rid of the for loop:
urls = map(lambda x:next(gen_url(url+x,"&show=more")),"xyz")
And it works. But I can only get to 001. Let's assume I want to reach 002; I am trying something like the following, but It doesn't work:
urls = imap((lambda x:next(gen_url(url+x,"&show=more")),"xyz"),2)
And this as well doesn't work:
urls = map((lambda x:next(gen_url(url+x,"&show=more")),"xyz"),repeat(2))
Could somebody explain me how to properly use the iterators in this case?
Functionally it would look like this:
def gen_url(prefix, suffix, id, places=3):
pattern = "{}{{:0{}d}}{}".format(prefix, places, suffix)
return pattern.format(id)
url = "www.testpage.com/"
a = [ gen_url(url + l, "&show=more", n) for l in "xyz" for n in range(1,4) ]
print a
So now your gen_url is a pure function that accepts everything from outside.
And your're generating a cartesian product (basically all permutations) of 2 sequences "xyz" and [1, 2, 3]
The script above generates:
['www.testpage.com/x001&show=more',
'www.testpage.com/x002&show=more',
'www.testpage.com/x003&show=more',
'www.testpage.com/y001&show=more',
'www.testpage.com/y002&show=more',
'www.testpage.com/y003&show=more',
'www.testpage.com/z001&show=more',
'www.testpage.com/z002&show=more',
'www.testpage.com/z003&show=more']
Prefix and suffix are detracting from the simple logic in gen_url.
They can be pulled out.
Try this:
from itertools import count, islice
def gen_url(places=3):
for i in count(1):
yield "{{:0{}d}}".format(places).format(i)
url = "www.testpage.com/"
list_of_urls = [url+c+x+"&show=more" for c in "xyz" for x in islice(gen_url(), 0, 2)]
Related
I'm trying to learn about lambda functions, I'm would like the code to:
add a slash '/' to the end of a string in list 'techCodeList'
add and append every item in 'finishList' to the every entry in 'techCodeList', appending to 'combinedCodeList' every time (so combinedCodeList = ['a/ABUL', 'a/BEL', 'a/PBL'] etc)
I could do it using other methods but I want to try using lambda, so would it be viable and if so how would I do it? My code is below:
#example shortened
class myClass:
def __init__(self):
self.techCodeList = ('a','b','c')
def applyCodes(self):
self.combinedCodeList = list()
finishList = ["ABUL","BEL","PBL","PBUL","ABL","SBL","SBSL","SBUL","PNP","SNP","PCP","SCP","NBP","ASP","ACP","SAL","SAS","AMB","CBP","HBN","MBL","MWL","HBB","SPE","PBUL/SAMPLE"]#list to append to techcodelist
len1 = len(self.combinedCodeList)
arrayCounter = 0
for i in self.techCodeList:
for _ in finishList:
print (arrayCounter)
self.techCodeList = list(map(lambda orig_string: orig_string + '/', self.techCodeList[arrayCounter]))
self.techCodeList = list(map(lambda orig_string: orig_string + finishList[arrayCounter], self.techCodeList[arrayCounter]))
self.combinedCodeList.append(self.techCodeList[arrayCounter])
if arrayCounter == len(self.techCodeList) - 1:
break
arrayCounter = arrayCounter + 1
print (self.combinedCodeList)
myClass()
And here is the result in the combinedCodeList:
['aABUL', '/BEL', '/BEL', '/BEL']
If you have any other suggestions for good habits or suggestions for my code please feel free to leave them too, I'm still very much learning. Thanks.
If I understood correctly you want to create an exchaustive combinations between all the entries from the tech code and finish lists.
For that you can use list comprehension like below:
tech_code_list = ["a", "b", "c"]
finish_list = ["ABUL","BEL","PBL","PBUL","ABL","SBL","SBSL","SBUL","PNP","SNP","PCP","SCP","NBP","ASP","ACP","SAL","SAS","AMB","CBP","HBN","MBL","MWL","HBB","SPE","PBUL/SAMPLE"]
combined_code_list = [
tech_code + "/" + finish for tech_code in tech_code_list for finish in finish_list
]
print(combined_code_list)
# will print: ['a/ABUL', 'a/BEL', 'a/PBL', 'a/PBUL', ... ]
iterools.product gives you all pairwise combinations from two lists. As you want to use lambda we do that in the map function
from itertools import product
list(map(lambda p: p[0] + '/' + p[1], product(tech_code_list, finish_list)))
output:
['a/ABUL',
'a/BEL',
'a/PBL',
'a/PBUL',
'a/ABL',
...
]
I would like to know if there is a better way to print all objects in a Python list than this :
myList = [Person("Foo"), Person("Bar")]
print("\n".join(map(str, myList)))
Foo
Bar
I read this way is not really good :
myList = [Person("Foo"), Person("Bar")]
for p in myList:
print(p)
Isn't there something like :
print(p) for p in myList
If not, my question is... why ? If we can do this kind of stuff with comprehensive lists, why not as a simple statement outside a list ?
Assuming you are using Python 3.x:
print(*myList, sep='\n')
You can get the same behavior on Python 2.x using from __future__ import print_function, as noted by mgilson in comments.
With the print statement on Python 2.x you will need iteration of some kind, regarding your question about print(p) for p in myList not working, you can just use the following which does the same thing and is still one line:
for p in myList: print p
For a solution that uses '\n'.join(), I prefer list comprehensions and generators over map() so I would probably use the following:
print '\n'.join(str(p) for p in myList)
I use this all the time :
#!/usr/bin/python
l = [1,2,3,7]
print "".join([str(x) for x in l])
[print(a) for a in list] will give a bunch of None types at the end though it prints out all the items
For Python 2.*:
If you overload the function __str__() for your Person class, you can omit the part with map(str, ...). Another way for this is creating a function, just like you wrote:
def write_list(lst):
for item in lst:
print str(item)
...
write_list(MyList)
There is in Python 3.* the argument sep for the print() function. Take a look at documentation.
Expanding #lucasg's answer (inspired by the comment it received):
To get a formatted list output, you can do something along these lines:
l = [1,2,5]
print ", ".join('%02d'%x for x in l)
01, 02, 05
Now the ", " provides the separator (only between items, not at the end) and the formatting string '02d'combined with %x gives a formatted string for each item x - in this case, formatted as an integer with two digits, left-filled with zeros.
To display each content, I use:
mylist = ['foo', 'bar']
indexval = 0
for i in range(len(mylist)):
print(mylist[indexval])
indexval += 1
Example of using in a function:
def showAll(listname, startat):
indexval = startat
try:
for i in range(len(mylist)):
print(mylist[indexval])
indexval = indexval + 1
except IndexError:
print('That index value you gave is out of range.')
Hope I helped.
I think this is the most convenient if you just want to see the content in the list:
myList = ['foo', 'bar']
print('myList is %s' % str(myList))
Simple, easy to read and can be used together with format string.
I recently made a password generator and although I'm VERY NEW to python, I whipped this up as a way to display all items in a list (with small edits to fit your needs...
x = 0
up = 0
passwordText = ""
password = []
userInput = int(input("Enter how many characters you want your password to be: "))
print("\n\n\n") # spacing
while x <= (userInput - 1): #loops as many times as the user inputs above
password.extend([choice(groups.characters)]) #adds random character from groups file that has all lower/uppercase letters and all numbers
x = x+1 #adds 1 to x w/o using x ++1 as I get many errors w/ that
passwordText = passwordText + password[up]
up = up+1 # same as x increase
print(passwordText)
Like I said, IM VERY NEW to Python and I'm sure this is way to clunky for a expert, but I'm just here for another example
Assuming you are fine with your list being printed [1,2,3], then an easy way in Python3 is:
mylist=[1,2,3,'lorem','ipsum','dolor','sit','amet']
print(f"There are {len(mylist):d} items in this lorem list: {str(mylist):s}")
Running this produces the following output:
There are 8 items in this lorem list: [1, 2, 3, 'lorem', 'ipsum',
'dolor', 'sit', 'amet']
OP's question is: does something like following exists, if not then why
print(p) for p in myList # doesn't work, OP's intuition
answer is, it does exist which is:
[p for p in myList] #works perfectly
Basically, use [] for list comprehension and get rid of print to avoiding printing None. To see why print prints None see this
To print each element of a given list using a single line code
for i in result: print(i)
You can also make use of the len() function and identify the length of the list to print the elements as shown in the below example:
sample_list = ['Python', 'is', 'Easy']
for i in range(0, len(sample_list)):
print(sample_list[i])
Reference : https://favtutor.com/blogs/print-list-python
you can try doing this: this will also print it as a string
print(''.join([p for p in myList]))
or if you want to a make it print a newline every time it prints something
print(''.join([p+'\n' for p in myList]))
Hi there so I am looking to build this python function with simple things like def, find etc. so far I know how to get the first part of the code.
Given a string such as "HELLODOGMEMEDOGPAPA", I will need to return a list that gives me three things:
Everything before the word dog which i will denote as before_dog
The word dog until dog appears again dog_todog
Everything after the second time dog appears will be denoted by after_todog
The list will be in the form [before_dog,dog_todog,after_todog].
so for example given ("HELLODOGMEMEDOGPAPADD") this will return the list
("HELLO","DOGMEME","DOGPAPADD")
another example would be ("HEYHELLOMANDOGYDOGDADDY") this would return the list
("HEYHELLOMAN","DOGY","DOGDADDY")
but if I have ("HEYHELLODOGDADDY")
the output will be ("HEYHELLO","DOGDADDY","")
also if dog never appears ("HEYHELLOYO") then the output will be ("HEYHELLOYO,"","")
This is what I have so far:
def split_list(words):
# declare the list
lst = []
# find the first position
first_pos=words.find("DOG")
# find the first_pos
before_dog = words [0:first_pos]
lst.append(before_dog)
return lst
Funny function split_2_dogs() with re.findall() function:
import re
def split_2_dogs(s):
if s.count('DOG') == 2: # assuring 2 dogs are "walking" there
return list(re.findall(r'^(.*)(DOG.*)(DOG.*)$', s)[0])
print(split_2_dogs("HELLODOGMEMEDOGPAPADD"))
print(split_2_dogs("HEYHELLOMANDOGYDOGDADDY"))
The output:
['HELLO', 'DOGMEME', 'DOGPAPADD']
['HEYHELLOMAN', 'DOGY', 'DOGDADDY']
Alternative solution with str.index() and str.rfind() functions:
def split_2_dogs(s):
if 'DOG' not in s: return [s,'']
pos1, pos2 = s.index('DOG'), s.rfind('DOG')
return [s[0:pos1], s[pos1:pos2], s[pos2:]]
This is pretty easy to do using the split function. For example, you can split any string by a delimiter, like dog, as so:
>>> chunks = 'HELLODOGMEMEDOGPAPA'.split('DOG')
>>> print(chunks)
['HELLO', 'MEME', 'PAPA']
You could then use the output of that in a list comprehension, like so:
>>> dog_chunks = chunks[:1] + ["DOG" + chunk for chunk in chunks[1:]]
>>> print(dog_chunks)
['HELLO', 'DOGMEME', 'DOGPAPA']
The only slightly tricky bit is making sure you don't prepend dog to the first string in the list, hence the little bits of slicing.
Split the string at 'DOG' and use conditions to get the desired result
s = 'HELLODOGMEMEDOGPAPADD'
l = s.split('DOG')
dl = ['DOG'+i for i in l[1:]]
[l[0]]+dl if l[0] else dl
Output:
['HELLO', 'DOGMEME', 'DOGPAPADD']
Splitting at DOG is the key!! This code will for all the cases that you have mentioned.
from itertools import izip_longest
words = 'HEYHELLODOGDADDY'
words = words.split("DOG")
words = ['DOG'+j if i>0 else j for i,j in enumerate(words)]
# words = ['HEYHELLO', 'DOGDADDY']
ans = ['','','']
# stitch words and ans together
ans = [m+n for m,n in izip_longest(words,ans,fillvalue='')]
print ans
Output :
['HEYHELLO', 'DOGDADDY', '']
I am making a String Rewriting Function that takes a string and rewrites it according to the rules in a dictionary. The code works perfectly fine once but I need it to call itself n times and print the 'nth' rewritten string. The code that works that I need to be recursive is:
S = "AB"
def srs_print(S, n, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
axiom = list(S)
key = []
value = []
output = ''
for k in rules:
#Inputs the keys of the rules dictionary into a new list
key.append(k)
#Inputs the value of the rules dictionary into a new list
value.append(rules[k])
for x in axiom:
if x in key:
axiomindex = key.index(x)
output += value[axiomindex]
else:
output += x
S = output
return S
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
#print(j)
#while len(range(n)) > 0:
# S = srs_print(S, n, rules)
# n = n-1
#print("The", n, "th rewrite is " )
#j = srs_print(S, 5, {'A':'AB', 'B': 'A'})
print(srs_print("A", 5, {'A':'AB', 'B': 'A'}))
This turns "A" into "AB" but I need it to put 'S' back into the function and run again 'n'times. As you can see, some of the commented code are lines I have tried to use but have failed.
I hope I've explained myself well enough.
If I understand correctly, you pass "n" to the function as a way to count how many times you need to call it.
You could probably get away with enclosing the whole body of the function in a for or a whileloop.
If you want it to be recursive anyway, here's how it could work:
You need to have "two" return statements for your function. One that returns the result (in your case, "S"), and another one, that returns srs_print(S, n-1, rules)
Ex:
if n > 0:
return srs_print(S, n-1, rules)
else:
return S
I suggest you take some time and read this, to get a better understanding of what you want to do and whether or not it is what you should do.
You definitly don't need recursion here. First let's rewrite your function in a more pythonic way:
def srs_transform(string, rules):
'''
A function that takes a dictionary as SRS rules and prints
the output
'''
# the short way:
# return "".join(rules.get(letter, letter) for letter in string)
# the long way
output = []
for letter in string:
transformed = rules.get(letter, letter)
output.append(transformed)
return "".join(output)
Now we add a wrapper function that will take care of applying srs_transform a given number of times to it's arguments:
def srs_multi_transform(string, rules, times):
output = string
for x in range(times):
output = srs_transform(output, rules)
return output
And now we just have to call it:
print(srs_transform("A", {'A':'AB', 'B': 'A'}, 5))
>> ABAABABAABAAB
Why not simply use a for-loop?
def srs_print(S, n, rules):
for _ in range(n):
S = ''.join(rules.get(x, x) for x in S)
return S
I am trying to provide a recursive method that provides a list of all the possible combinations when given a list of courses. E.g course = [Entree, Dessert]
This is what I have so far:
Entree = ["pumkinsoup","antipasto"]
Dessert = ["cheesecake", "icecream", "tiramisu", "cheeseplatter"]
courses = [Entree, Dessert]
def make_orders(courses):
dishes_so_far = []
recursive_make_orders(dishes_so_far, courses)
def recursive_make_orders(dishes_so_far, courses):
n = len(courses)
if n==0 :
print(dishes_so_far)
else:
current_courses = courses[0]
for D in current_courses:
dishes_so_far.append(D)
recursive_make_orders(dishes_so_far , courses[1:len(courses)])
\I am trying to make it so that it prints out the combination like [[pumkinsoup,cheesecake],[punkinsoup, icecream]] and etc but its actually giving me [pumkinsoup, cheesecake, icecream] and so on.
Tried adding it with addition instead of append and it gave me an error.
This is homework, so a recursive method is required.
You're not too far off - use itertools.product and *courses to unpack to it:
from itertools import product
for course in product(*courses):
print course
('pumkinsoup', 'cheesecake')
('pumkinsoup', 'icecream')
('pumkinsoup', 'tiramisu')
('pumkinsoup', 'cheeseplatter')
('antipasto', 'cheesecake')
('antipasto', 'icecream')
('antipasto', 'tiramisu')
('antipasto', 'cheeseplatter')
If you want recursive version, you can do something like this:
def worker(entree, dessert):
d = []
if not entree or not dessert: return d
d.append((entree[0], dessert[0]))
d += worker(entree[1:], dessert)
d += worker(entree, dessert[1:])
return d
Your version is not working as you said because courses now a list of lists, and courses[0] is just Entree, so you recursively constructiong new list from Entree.