I'm trying to do the following:
>>>func = lambda string,i=0: string[index]
>>> func('HEY')
H
>>> func('HEY')
E
>>> func('HEY')
Y
How can i save and increment index each time(without creating index as global)
thanks
Solution 1
You can create a generator function, like this
def get_next_char(actual_string):
for char in actual_string:
yield char
Then, you need to create a generator object, like this
next_char = get_next_char("HEY")
That's it. You can now get the next character with next function, like this
>>> next(next_char)
H
>>> next(next_char)
E
>>> next(next_char)
Y
Solution 2
You can simply use the String's iterator, like this
get_char = iter("HEY")
>>> next(get_char)
H
>>> next(get_char)
E
>>> next(get_char)
Y
Related
I'm splitting a string into two of which I know for certain, the 2nd one will be the representation of an integer. I want to unpack both values and immediately cast the 2nd value to int. Basically I want this code in one line:
a, b = x.split('foo')
b = int(b)
I searched the web among SO, but looking for something containing python multiple return values only returns sites explaining how to return multiple values at once. Then I came up with that:
a, b = [value if i == 0 else int(value) for i, value in enumerate(f())]
but that's an abomination I'd like to avoid.
So is there a way to actually cast one of multiple return values of a function on the fly?
If you want a short one-liner to make your code readable, compact, and neat, defining your own function is a good option. The definition of the function can take up space elsewhere (even in a module), while your main script stays uncluttered.
def str_int(my_string):
a, b = my_string.split()
b = int(b)
return a, b
Then the call to this function is a short one-liner.
a, b = str_int(my_string)
One more option with list comprehension:
x = 'test 1'
a, b = [(a, int(b)) for a, b in [x.split()]][0]
print(type(a), a, type(b), b)
# output: <class 'str'> test <class 'int'> 1
You can use map function as below:
my_str = 'item 1'
a, b = map(lambda x : int(x) if x.isdigit() else x, my_str.split())
With Python 3.8's assignment expressions you can use this abomination:
x = '4foobar'
a, b = int((y := x.split('foo'))[0]), y[1]
# a = 4, b = 'bar'
Though obviously this is convoluted and prone to error. Just use a two liner.
So in my code there is a list called l. I then typed l(b) = l(b), X(a). That was supposed to make the item b in l turn into item b in l joined with the letter a in X. But python thinks l(b) is a function. It thinks b is the parameter and l is the function name. How do I fix it?
Switching the sides.
a = 0
b = 0
l = list()
while a <= len(X):
while not X(a)==' ':
l(b) = l(b),X(a)
l.append()
b = b + 1
To get element b in list l, use brackets [] instead of parens ().
So that means l[b], not l(b).
Question has been asked that is similar but all post on here refer to replacing single characters. I'm trying to replace a whole word in a string. I've replaced it but I cant print it with spaces in between.
Here is the function replace that replaces it:
def replace(a, b, c):
new = b.split()
result = ''
for x in new:
if x == a:
x = c
result +=x
print(' '.join(result))
Calling it with:
replace('dogs', 'I like dogs', 'kelvin')
My result is this:
i l i k e k e l v i n
What I'm looking for is:
I like kelvin
The issue here is that result is a string and when join is called it will take each character in result and join it on a space.
Instead, use a list , append to it (it's also faster than using += on strings) and print it out by unpacking it.
That is:
def replace(a, b, c):
new = b.split(' ')
result = []
for x in new:
if x == a:
x = c
result.append(x)
print(*result)
print(*result) will supply the elements of the result list as positional arguments to print which prints them out with a default white space separation.
"I like dogs".replace("dogs", "kelvin") can of course be used here but I'm pretty sure that defeats the point.
Substrings and space preserving method:
def replace(a, b, c):
# Find all indices where 'a' exists
xs = []
x = b.find(a)
while x != -1:
xs.append(x)
x = b.find(a, x+len(a))
# Use slice assignment (starting from the last index)
result = list(b)
for i in reversed(xs):
result[i:i+len(a)] = c
return ''.join(result)
>>> replace('dogs', 'I like dogs dogsdogs and hotdogs', 'kelvin')
'I like kelvin kelvinkelvin and hotkelvin'
Just make result a list, and the joining will work:
result = []
You are just generating one long string and join its chars.
I need to be able to cycle through a string of characters using the modulo operator so that each character can be passed to a function. This is a simple question, I know, but I am seriously confused as to how to do it. Here is what I have but it gives me the error "TypeError: not all arguments converted during string formatting". Any suggestions would be appreciated.
key = 'abc'
def encrypt(key,string):
c = ''
for i in range(0,len(string)):
t = (key)%3
a = XOR(ord(string[i]),ord(t))
b = chr(a)
c = c + b
return(c)
Ingredients
Here are some ingredients which help you write your encrypt function in a concise way:
You can directly iterate over the characters of a string:
>>> my_string = 'hello'
>>> for c in my_string:
... print(c)
...
h
e
l
l
o
You can cycle through any iterable (like, for example, a string) using the cycle function from the itertools module of the standard library:
>>> from itertools import cycle
>>> for x in cycle('abc'):
... print(x)
...
a
b
c
a
b
c
a
# goes on infinitely, abort with Ctrl-C
You can use the zip function to iterate over two sequences at the same time:
>>> for a, b in zip('hello', 'world'):
... print(a, b)
...
h w
e o
l r
l l
o d
Edit: as kichik suggests, you can also use itertools.izip which is beneficial if you deal with very large input strings.
You calculate the xor of two numbers by using the ^ operator:
>>> 5 ^ 3
6
You can concatenate a sequence of individual strings to a single string using the join function:
>>> ''.join(['hello', 'how', 'are', 'you'])
'hellohowareyou'
You can feed join with a so-called generator expression, which is similar to a for loop, but as a single expression:
>>> ''.join(str(x+5) for x in range(3))
'567'
Putting it all together
from itertools import cycle, izip
def encrypt(key, string):
return ''.join(chr(ord(k) ^ ord(c))
for k, c in izip(cycle(key), string))
You can (probably should) iterate over the characters without using range() and you'll want to run ord() on each character before you run mod on it, as the % operator means something else for a string. This should work:
key = 'abc'
for c in key:
print XOR(ord(c), ord(c) % 3)
You can use itertools.cycle() to cycle through the key and itertools.izip() for an easy combination of the two.
import itertools
def encrypt(key, string):
keyi = itertools.cycle(key)
result = ''
for k, v in itertools.izip(keyi, string):
a = ord(v) ^ ord(k)
result += chr(a)
return result
And then use it like this:
>>> encrypt('\x00', 'abc')
'abc'
>>> encrypt('\x01', 'abc')
'`cb'
You got an error about formatting because % is not a modulo operator for strings. It's used for formatting strings. You probably meant to use something like this:
key[i%3]
def __init__(self,emps=str(""),l=[">"]):
self.str=emps
self.bl=l
def fromFile(self,seqfile):
opf=open(seqfile,'r')
s=opf.read()
opf.close()
lisst=s.split(">")
if s[0]==">":
lisst.pop(0)
nlist=[]
for x in lisst:
splitenter=x.split('\n')
splitenter.pop(0)
splitenter.pop()
splitstring="".join(splitenter)
nlist.append(splitstring)
nstr=">".join(nlist)
nstr=nstr.split()
nstr="".join(nstr)
for i in nstr:
self.bl.append(i)
self.str=nstr
return nstr
def getSequence(self):
print self.str
print self.bl
return self.str
def GpCratio(self):
pgenes=[]
nGC=[]
for x in range(len(self.lb)):
if x==">":
pgenes.append(x)
for i in range(len(pgenes)):
if i!=len(pgenes)-1:
c=krebscyclus[pgenes[i]:pgenes[i+1]].count('c')+0.000
g=krebscyclus[pgenes[i]:pgenes[i+1]].count('g')+0.000
ratio=(c+g)/(len(range(pgenes[i]+1,pgenes[i+1])))
nGC.append(ratio)
return nGC
s = Sequence()
s.fromFile('D:\Documents\Bioinformatics\sequenceB.txt')
print 'Sequence:\n', s.getSequence(), '\n'
print "G+C ratio:\n", s.GpCratio(), '\n'
I dont understand why it gives the error:
in GpCratio for x in range(len(self.lb)): AttributeError: Sequence instance has no attribute 'lb'.
When i print the list in def getSequence it prints the correct DNA sequenced list, but i can not use the list for searching for nucleotides. My university only allows me to input 1 file and not making use of other arguments in definitions, but "self"
btw, it is a class, but it refuses me to post it then.. class called Sequence
Looks like a typo. You define self.bl in your __init__() routine, then try to access self.lb.
(Also, emps=str("") is redundant - emps="" works just as well.)
But even if you correct that typo, the loop won't work:
for x in range(len(self.bl)): # This iterates over a list like [0, 1, 2, 3, ...]
if x==">": # This condition will never be True
pgenes.append(x)
You probably need to do something like
pgenes=[]
for x in self.bl:
if x==">": # Shouldn't this be != ?
pgenes.append(x)
which can also be written as a list comprehension:
pgenes = [x for x in self.bl if x==">"]
In Python, you hardly ever need len(x) or for n in range(...); you rather iterate directly over the sequence/iterable.
Since your program is incomplete and lacking sample data, I can't run it here to find all its other deficiencies. Perhaps the following can point you in the right direction. Assuming a string that contains the characters ATCG and >:
>>> gene = ">ATGAATCCGGTAATTGGCATACTGTAG>ATGATAGGAGGCTAG"
>>> pgene = ''.join(x for x in gene if x!=">")
>>> pgene
'ATGAATCCGGTAATTGGCATACTGTAGATGATAGGAGGCTAG'
>>> ratio = float(pgene.count("G") + pgene.count("C")) / (pgene.count("A") + pgene.count("T"))
>>> ratio
0.75
If, however, you don't want to look at the entire string but at separate genes (where > is the separator), use something like this:
>>> gene = ">ATGAATCCGGTAATTGGCATACTGTAG>ATGATAGGAGGCTAG"
>>> genes = [g for g in gene.split(">") if g !=""]
>>> genes
['ATGAATCCGGTAATTGGCATACTGTAG', 'ATGATAGGAGGCTAG']
>>> nGC = [float(g.count("G")+g.count("C"))/(g.count("A")+g.count("T")) for g in genes]
>>> nGC
[0.6875, 0.875]
However, if you want to calculate GC content, then of course you don't want (G+C)/(A+T) but (G+C)/(A+T+G+C) --> nGC = [float(g.count("G")+g.count("C"))/len(g)].