long story short. Can someone explain it to me how is it that be, simple line of code can do the same as all of the for loop written by me?
def z1(code1, code2):
parse = lambda x: int(x.replace('-', ''))
code1, code2 = parse(code1), parse(code2)
print(code1, code2)
return ["%02d-%03d" % divmod(x, 1000) for x in range(code1, code2+1)] <---
here's my solution:
def z2(code1, code2):
codes = []
parse = lambda x: int(x.replace('-', ''))
code1, code2= parse(code1), parse(code2)
for x in range(code1, code2+1):
x = str(x)
a = x[0:2]
b = x[2:6]
c = a+"-"+b
codes.append(f"{c}")
return codes
["%02d-%03d" % divmod(x, 1000) for x in range(code1, code2+1)]
This is called list comprehension, allow writing more concise code than creating empty list and then append-ing in loop. Consider following example
squares = []
for i in range(5):
squares.append(i**2)
is equivalent to
squares = [i**2 for i in range(5)]
Related
I have created a for loop to create a list containing the string 'size_i' so I have size_01, size_02, size_03 etc all the way to size_84. Like:
def size():
x = list()
for i in range(0,84):
x = x.append('size' + str(i))
return x
This works fine. Now I want to save each 'size' in that list to the end of a filepath:
d_path = /home/Jake/Documents/sizes/size_01
= /home/Jake/Documents/sizes/size_02
etc...
But for some reason I can't get it to work and I have no idea where I am going wrong! Here is my full attempt:
import os
def size():
d_path = '/home/Jake/Documents/sizes'
x = list()
for i in range(0,84):
x = x.append('size_' + str(i))
p = os.path.join(d_path,x)
return p
From what I understand of the question, you are writing your function wrong. x.append('size_' + str(i)) returns None, so basically you were replacing x with None in x = x.append('size_' + str(i)) which was giving an error when you were trying to join.
Your current function is returning the last name that you are trying to create ie '/home/Jake/Documents/sizes/size_83', i believe you want to return a list containing all the names.
This will work.
import os
def size():
d_path = '/home/Jake/Documents/sizes'
x = list()
for i in range(0,84):
tmp = 'size_' + str(i)
p = os.path.join(d_path,tmp)
x.append(p)
return x
print size()
Does this work for you?
import os
def size():
d_path = '/home/Jake/Documents/sizes'
x = []
p = []
for i in range(0,84):
z = 'size_' + str(i)
x.append(z)
p.append(d_path+z)
return p
Try this one
import os
def size():
d_path = '/home/Jake/Documents/sizes'
x = list()
for i in range(0,84):
x.append(os.path.join(d_path,'size_' + str(i)))
return x
The function append in class list doesn't return a
significant value.
Try this:
import os
def size():
d_path = '/home/Jake/Documents/sizes'
x = []
p=[]
for i in range(0,84):
x.append('size_{:02}'.format(i))
p.append(os.path.join(d_path,x[i]))
return p
print size()
Some of these answers are unnecessarily long and complex, but may more be insightful about what's going on than the following snippets:
Clear Approach
path_root = "/home/Jake/Documents/sizes"
sizes = ["size_%d" % i for i in range(84)]
paths = [os.path.join(path_root, s) for s in sizes]
print(paths)
Alternative Approach
path_root = "/home/Jake/Documents/sizes"
paths = [os.path.join(path_root, "size_%d" % i) for i in range(84)]
print(paths)
Some notes:
Both approaches use list comprehensions
When the lower bound of range is zero, it can be omitted
Both approaches use the % sign printf-style string formatting operator
If you want leading zeros for single digit numbers like your comments (but not your code) suggest, you can replace "size_%d" with "size_%02d"
I have a list X containing the data of N users. I want to have the relative frequency distribution of each user.
l1 = list()
for i in range(0,N):
tmp = np.array(X[i])
tmp = tmp[tmp < tr]
tmp = np.histogram(tmp, x)
l1.append(tmp[0]/sum(tmp[0]))
Is there any way to avoid this loop?
Use map:
def op(A):
tmp = np.array(A)
tmp = tmp[tmp < tr]
tmp = np.histogram(tmp, x)
return tmp[0]/sum(tmp[0])
# creates a generator
map(op, X)
# or, to get a list
l1 = list(map(op, X))
I think that I got what you are asking for: How to avoid using range and also avoid appeding to l1. If this is your case you may use a generator, try this:
def iter_on_items(X):
for item in X:
tmp = np.array(item)
tmp = tmp[tmp < tr]
tmp = np.histogram(tmp, x)
yield tmp[0]/sum(tmp[0])
Then you will need to consume it by doing this:
for result in iter_on_items(X):
print(result)
What about using map? This is a builtin in function that accepts as input a function and an iterable and goes through applying the function to each element in the iterable. I've directly translated what you have above, but you could combine these into less map calls.
l1 = list(map(lambda a: np.array(a), X))
l1 = list(map(lambda a: a[a < tr], l1))
l1 = list(map(lambda a: np.histogram(a, X), l1))
l1 = list(map(lambda a: a[0]/sum(a[0]), l1))
I have the program below, which is passed on to another function which simply prints out the original and encrypted messages. I want to know how I can simplify this program, specifically the "match = zip" and "change = (reduce(lambda" lines. If possible to do this without using lambda, how can I?
from itertools import cycle
alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
def vigenereencrypt(message,keyword):
output = ""
match = zip(message.lower(),cycle(keyword.lower()))
for i in match:
change = (reduce(lambda x, y: alphabet.index(x) + alphabet.index(y), i)) % 26
output = output + alphabet[change]
return output.lower()
Two things:
You dont need to have a local variable match, just loop zip
Your can split up your two indices x and y in your for loop definition rather than using reduce; reduce is normally used for larger iterables and since you only have 2 items in i, it's adding unnecessary complexity.
ie, you can change your for loop definition to:
for x, y in zip(...):
and your definition of change to:
change = (alphabet.index(x) + alphabet.index(y)) % 26
Starting with what R Nar said:
def vigenereencrypt(message,keyword):
output = ""
for x, y in zip(message.lower(), cycle(keyword.lower())):
change = (alphabet.index(x) + alphabet.index(y)) % 26
output = output + alphabet[change]
return output.lower()
We can be more efficient by using a list and then joining it, instead of adding to a string, and also by noticing that the output is already lowercase:
def vigenereencrypt(message,keyword):
output = []
for x, y in zip(message.lower(), cycle(keyword.lower())):
change = (alphabet.index(x) + alphabet.index(y)) % 26
output.append(alphabet[change])
return "".join(output)
Then we can reduce the body of the loop to one line..
def vigenereencrypt(message,keyword):
output = []
for x, y in zip(message.lower(), cycle(keyword.lower())):
output.append(alphabet[(alphabet.index(x) + alphabet.index(y)) % 26])
return "".join(output)
... so we can turn it into a list comprehension:
def vigenereencrypt(message,keyword):
output = (
alphabet[(alphabet.index(x) + alphabet.index(y)) % 26]
for x, y in zip(message.lower(), cycle(keyword.lower()))
)
return "".join(output)
I feel like there's something we could do with map(alphabet.index, ...) but I can't think of a way that's any better than the list comprehension.
you could do it with a bunch of indexing instead of zip...
alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
alphaSort = {k:n for n,k in enumerate(alphabet)}
alphaDex = {n:k for n,k in enumerate(alphabet)}
def vigenereencrypt(message,keyword):
output = ""
#match = zip(message.lower(),cycle(keyword.lower())) # zip(a,cycle(b)) Creates [(a[n],b[n%len(b)]) for k in range(len(a)) ]
op = "" # So lets start with for k in range(len(a))
for k in range(len(message)):
op += alphaDex[(alphaSort[message.lower()[k]]+alphaSort[keyword.lower()[k%len(keyword)]])%len(alphabet)]
return(op)
I have some problems with parsing the correct way. I want to split the complete string in two seperate strings. And then remove the "="-signs frome the first string and the ","-sign from the 2nd string. From my output I can conclude that I did something wrong, but I do not seem to get where the problem lies. I want the first part to convert to integers, and I've already tried it with map(int, split()).
If anyone has a tip, I would appreciate that.
This is my output:
('5=20=22=10=2=0=0=1=0=1', 'Vincent Appel,Johannes Mondriaan')
This is my program:
mystring = "5=20=22=10=2=0=0=1=0=1;Vincent Appel,Johannes Mondriaan"
def split_string(mystring):
strings = mystring.split(";")
x = strings[0]
y = strings[-1]
print(x,y)
def split_scores(x):
scores = x.split("=")
score = scores[0]
names = scores[-1]
stnames(names)
print score
def stnames(y):
studentname = y.split(",")
name = studentname[1]
print name
split_string(mystring)
split_string(mystring) runs the 1st function, producing the tuple with 2 strings. But nothing runs the other functions which are intended to perform further splitting.
try:
x, y = split_string(mystring)
x1 = split_scores(x)
y1 = stnames(y)
(x1, y1)
oops, your functions print the results, don't return them. So you also need:
def split_string(mystring):
# split mystring on ";"
strings = mystring.split(";")
return strings[0],strings[1]
def split_string(mystring):
# this version raises an error if mystring does not have 2 parts
x, y = mystring.split(";")
return x,y
def split_scores(x):
# return a list with all the scores
return x.split("=")
def stnames(y):
# return a list with all names
return y.split(",")
def lastname(y):
# return the last name (, delimited string)
return y.split(",")[-1]
If you are going to split the task among functions, it is better to have them return the results rather than print them. That way they can be used in various combinations. print within a function only for debugging purposes.
Or a compact, script version:
x, y = mystring.split(';')
x = x.split('=')
y = y.split(',')[-1]
print y, x
If you want the scores as numbers, add:
x = [int(x) for x in x]
to the processing.
Try this:
def split_string(mystring):
strings = mystring.split(";")
x = int(strings[0].replace("=",""))
y = strings[-1].replace(","," ")
print x,y
My two cents.
If I understood what you want to achieve, this code could help:
mystring = "5=20=22=10=2=0=0=1=0=1;Vincent Appel,Johannes Mondriaan"
def assignGradesToStudents(grades_and_indexes, students):
list_length = len(grades_and_indexes)
if list_length%2 == 0:
grades = grades_and_indexes[:list_length/2]
indexes = grades_and_indexes[list_length/2:]
return zip([students[int(x)] for x in indexes], grades)
grades_and_indexes, students = mystring.split(';')
students = students.split(',')
grades_and_indexes = grades_and_indexes.split('=')
results = assignGradesToStudents(grades_and_indexes, students)
for result in results:
print "[*] {} got a {}".format(result[0], result[1])
Output:
[*] Vincent Appel got a 5
[*] Vincent Appel got a 20
[*] Johannes Mondriaan got a 22
[*] Vincent Appel got a 10
[*] Johannes Mondriaan got a 2
As part of some simulations I'm running I need to output the cumulative distribution of the output of some algorithms:
tests = []
numtests = 100
for i in range(0, numtests):
#random
zeros = [0] * 1024
ones = [1] * 10
#ones = [randint(0,1023) for _ in range(0,10)]
input = zeros + ones
shuffle(input)
tests.append(HGBSA(input,10))
count = [x[0] for x in tests]
found = [x[1] for x in tests]
found.sort()
num = Counter(found)
freqs = [x for x in num.values()]
cumsum = [sum(item for item in freqs[0:rank+1]) for rank in range(len(freqs))]
normcumsum = [float(x)/numtests for x in cumsum]
print(freqs)
print(cumsum)
print(normcumsum)
print(sorted(num.keys()))
figure(0)
plt.plot(sorted(num.keys()), normcumsum)
plt.xlim(0,100)
plt.show()
As the above code shows, I'm running my algorithm 100 times with randomly generated input and then creating a cumulative distribution from the results.
I want to do a similar thing with other algorithms, and in c++ I could write a template class/template function which took a (pointer to a) method as am argument.
I'd like to ask if there is a way in python to create a function/class which produces the output I want, but takes a function as an input, so I avoid duplicating code all over the place.
This is simple to do in Python. You can pass functions (or classes) around like anything else.
def run_test(test_function):
tests = []
numtests = 100
for i in range(0, numtests):
#random
zeros = [0] * 1024
ones = [1] * 10
#ones = [randint(0,1023) for _ in range(0,10)]
input = zeros + ones
shuffle(input)
tests.append(test_function(input,10))
count = [x[0] for x in tests]
found = [x[1] for x in tests]
found.sort()
num = Counter(found)
freqs = [x for x in num.values()]
cumsum = [sum(item for item in freqs[0:rank+1]) for rank in range(len(freqs))]
normcumsum = [float(x)/numtests for x in cumsum]
print(freqs)
print(cumsum)
print(normcumsum)
print(sorted(num.keys()))
figure(0)
plt.plot(sorted(num.keys()), normcumsum)
plt.xlim(0,100)
plt.show()
run_test(HGBSA)
run_test(SOME_OTHER_FUNCTION)
I am not sure that i understand the question, but sounds like you want to pass a function as function argument? You can do that right of the bat in python as everything is passed by reference and nothing stops you from passing a reference to a function as an argument.