increasing string size through loop - python

what's a simple way to increase the length of a string to an arbitrary integer x? like 'a' goes to 'z' and then goes to 'aa' to 'zz' to 'aaa', etc.

That should do the trick:
def iterate_strings(n):
if n <= 0:
yield ''
return
for c in string.ascii_lowercase:
for s in iterate_strings(n - 1):
yield c + s
It returns a generator.
You can iterate it with a for loop:
for s in iterate_strings(5)
Or get a list of the strings:
list(iterate_strings(5))
If you want to iterate over shorter strings too, you can use this function:
def iterate_strings(n):
yield ''
if n <= 0:
return
for c in string.ascii_lowercase:
for s in iterate_strings(n - 1):
yield c + s

Here's my solution, similar to Adam's, except it's not recursive. :].
from itertools import product
from string import lowercase
def letter_generator(limit):
for length in range(1, limit+1):
for letters in product(lowercase, repeat=length):
yield ''.join(letters)
And it returns a generator, so you can use a for loop to iterate over it:
for letters in letter_generator(5):
# ...
Have fun!
(This is the second time today I found itertools.product() useful. Woot.)

You can multiply the string in the integer.
For example
>>> 'a' * 2
'aa'
>>> 'a' * 4
'aaaa'
>>> 'z' * 3
'zzz'
>>> 'az' * 3
'azazaz'

Define x. I am using x = 5 for this example.
x = 5
import string
for n in range(1,x+1):
for letter in string.ascii_lowercase:
print letter*n

Related

Create alphabetically ascending list

I want to create alphabetically ascending names like the column names in excel. That is I want to have smth. like a,b,c,...,z,aa,ab,...az,...zz,aaa,aab,....
I have tried:
for i in range(1000):
mod = int(i%26)
div = int(i/26)
print(string.ascii_lowercase[div]+string.ascii_lowercase[mod])
Which works until zz but than fails because it runs out of index
aa
ab
ac
ad
ae
af
ag
ah
ai
aj
ak
al
.
.
.
zz
IndexError
You could make use of itertools.product():
from itertools import product
from string import ascii_lowercase
for i in range(1, 4):
for x in product(ascii_lowercase, repeat=i):
print(''.join(x))
First, you want all letters, then all pairs, then all triplets, etc. This is why we first need to iterate through all the string lengths you want (for i in range(...)).
Then, we need all possible associations with the i letters, so we can use product(ascii_lowercase) which is equivalent to a nested for loop repeated i times.
This will generate the tuples of size i required, finally just join() them to obtain a string.
To continuously generate names without limit, replace the for loop with while:
def generate():
i = 0
while True:
i += 1
for x in product(ascii_lowercase, repeat=i):
yield ''.join(x)
generator = generate()
next(generator) # 'a'
next(generator) # 'b'
...
For a general solution we can use a generator and islice from itertools:
import string
from itertools import islice
def generate():
base = ['']
while True:
next_base = []
for b in base:
for i in range(26):
next_base.append(b + string.ascii_lowercase[i])
yield next_base[-1]
base = next_base
print('\n'.join(islice(generate(), 1000)))
And the output:
a
b
c
...
z
aa
ab
...
zz
aaa
aab
...
And you can use islice to take as many strings as you need.
Try:
>>import string
>>string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>len(string.ascii_lowercase)
26
When your index in below line exceed 26 it raise exception
div = int(i/26)
, becouse of ascii_lowercase length:
But you can:
for i in range(26*26): # <--- 26 is string.ascii_lowercase
mod = int(i%26)
div = int(i/26)
print(string.ascii_lowercase[div]+string.ascii_lowercase[mod])
EDIT:
or you can use:
import string
n = 4 # number of chars
small_limit = len(string.ascii_lowercase)
limit = small_limit ** n
i = 0
while i < limit:
s = ''
for c in range(n):
index = int(i/(small_limit**c))%small_limit
s += string.ascii_lowercase[index]
print(s)
i += 1
You can use:
from string import ascii_lowercase
l = list(ascii_lowercase) + [letter1+letter2 for letter1 in ascii_lowercase for letter2 in ascii_lowercase]+ [letter1+letter2+letter3 for letter1 in ascii_lowercase for letter2 in ascii_lowercase for letter3 in ascii_lowercase]
There's an answer to this question provided on Code Review SE
A slight modification to the answer in the link gives the following which works for an arbitrary number of iterations.
def increment_char(c):
return chr(ord(c) + 1) if c != 'z' else 'a'
def increment_str(s):
lpart = s.rstrip('z')
num_replacements = len(s) - len(lpart)
new_s = lpart[:-1] + increment_char(lpart[-1]) if lpart else 'a'
new_s += 'a' * num_replacements
return new_s
s = ''
for _ in range(1000):
s = increment_str(s)
print(s)

Counting differences between two strings

I'm trying to count the number of differences between two imported strings (seq1 and seq2, import code not listed), but am getting no result when running the program. I want the output to read something like "2 differences." Not sure where I'm going wrong...
def difference (seq1, seq2):
count = 0
for i in seq1:
if seq1[i] != seq2[i]:
count += 1
return (count)
print (count, "differences")
You could do this pretty flatly with a generator expression
count = sum(1 for a, b in zip(seq1, seq2) if a != b)
If the sequences are of a different length, then you may consider the difference in length to be difference in content (I would). In that case, tag on an extra piece to account for it
count = sum(1 for a, b in zip(seq1, seq2) if a != b) + abs(len(seq1) - len(seq2))
Another weirdish way to write that which takes advantage of True being 1 and False being 0 is:
sum(a != b for a, b in zip(seq1, seq2))+ abs(len(seq1) - len(seq2))
zip is a python builtin that allows you to iterate over two sequences at once. It will also terminate on the shortest sequence, observe:
>>> seq1 = 'hi'
>>> seq2 = 'world'
>>> for a, b in zip(seq1, seq2):
... print('a =', a, '| b =', b)
...
a = h | b = w
a = i | b = o
This will evaluate similar to sum([1, 1, 1]) where each 1 represents a difference between the two sequences. The if a != b filter causes the generator to only produce a value when a and b differ.
When you say for i in seq1 you are iterating over the characters, not the indexes. You can use enumerate by saying for i, ch in enumerate(seq1) instead.
Or even better, use the standard function zip to go through both sequences at once.
You also have a problem because you return before you print. Probably your return needs to be moved down and unindented.
in your script there are to mistakes
"i" should be integer, not char
"return" should be in function the same level as print, not in cycle "for"
try not to use "print" in such way in functions
here is working version:
def difference (seq1, seq2):
count = 0
for i in range(len(seq1)):
if seq1[i] != seq2[i]:
count += 1
return (count)
So I had to do what you are asking to do and I came up with a very simple solution. Mine is a little different because I check the string to see which is bigger and put them in the correct variable for comparison later. All done with Vanilla python:
#Declare Variables
a='Here is my first string'
b='Here is my second string'
notTheSame=0
count=0
#Check which string is bigger and put the bigger string in C and smaller string in D
if len(a) >= len(b):
c=a
d=b
if len(b) > len(a):
d=a
c=b
#While the counter is less than the length of the longest string, compare each letter.
while count < len(c):
if count == len(d):
break
if c[count] != d[count]:
print(c[count] + " not equal to " + d[count])
notTheSame = notTheSame + 1
else:
print(c[count] + " is equal to " + d[count])
count=count+1
#the below output is a count of all the differences + the difference between the 2 strings
print("Number of Differences: " + str(len(c)-len(d)+notTheSame))
Correct code would be:
def difference(seq1, seq2):
count = 0
for i in range(len(seq1)):
if seq1[i] != seq2[i]:
count += 1
return count
First the return statement is done at the end of the function, therefore it should not be part of the for loop or the for loop would just run once.
Second the for loop wasn't correct because you weren't really telling giving the for loop an integer, therefore the correct code would be to give it a range the length of seq1, so:
for i in range(len(seq1)):

Change one character at a time in a string, don't change the string?

I have a string:
'ABCDEFGH'
I want to cycle through the string and, one by one, replace each character with one of 4 characters (1,2,3,4):
'ABCDEFGH'
'1BCDEFGH'
'A1CDEFGH'
'AB1DEFGH'
etc
'2BCDEFGH'
'A2CDEFGH'
'AB2DEFGH'
etc and so forth. However everytime I try, I end up altering the original string and my output ends up being strings of 1s!
'1111111'
Example code below:
letters = 'ABCDEFGH'
s = list(letters)
y = 0
while y < len(s):
s[y] = '1'
y = y + 1
Rather than change a list you reuse between iterations, produce a new list each time and replace the one character:
for i in range(len(letters)):
s = list(letters)
s[i] = '1'
print(''.join(s))
You can combine this with a nested loop:
for digit in '1234':
for i in range(len(letters)):
s = list(letters)
s[i] = digit
print(''.join(s))
In essence you are creating the product of '1234' and a position from range(len(letters)), so you could use itertools.product() to make that a single loop:
from itertools import product
for digit, pos in product('1234', range(len(letters))):
s = list(letters)
s[pos] = digit
print(''.join(s))
With a little enumerate() trickery you could make this a one-liner generator expression to produce all combinations:
from itertools import product
all_combos = (
''.join([digit if i == pos else c for i, c in enumerate(letters)])
for digit, pos in product('1234', range(len(letters))))
This builds a new list on the fly by iteration over letters, swapping out the one character at position pos for the digit.
Demo:
>>> from itertools import product
>>> letters = 'ABCDEFGH'
>>> all_combos = (
... ''.join([digit if i == pos else c for i, c in enumerate(letters)])
... for digit, pos in product('1234', range(len(letters))))
>>>
>>> next(all_combos)
'1BCDEFGH'
>>> next(all_combos)
'A1CDEFGH'
>>> next(all_combos)
'AB1DEFGH'
>>> next(all_combos)
'ABC1EFGH'
>>> from itertools import islice
>>> print(list(islice(all_combos, 10)))
['ABCD1FGH', 'ABCDE1GH', 'ABCDEF1H', 'ABCDEFG1', '2BCDEFGH', 'A2CDEFGH', 'AB2DEFGH', 'ABC2EFGH', 'ABCD2FGH', 'ABCDE2GH']
Reinitialize the list each time.
while y < len(letters):
s = list(letters)
s[y] = '1'
y = y + 1
dosomethingwith(s)
string = 'ABCDEFG'
dig = []
for i in range(1,8):
dig.append(str(i))
for letter in string[:]:
print string.replace(letter,dig[i-1])

Python: replace every letter except the nth letters in a string with a period(or another character)

So I have looked at the replace every nth letter and could not figure out the reverse. I started with this and quickly realized it would not work:
s = input("Enter a word or phrase: ")
l = len(s)
n = int(input("choose a number between 1 and %d: " %l))
print (s[0] + "." * (n-1)+ s[n]+ "." * (n-1) + s[n*2])
any help would be appreciated.
Let s be the original string and n the position not to be replaced.
''.join (c if i == n else '.' for i, c in enumerate (s) )
If the user enters 3, I'm assuming you want to replace the third, sixth, ninth...letter, right? Remember that indices are counted from 0:
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> remove = 3
>>> "".join(c if (i+1)%remove else "." for i,c in enumerate(s))
'ab.de.gh.jk.mn.pq.st.vw.yz'
Or, if you meant the opposite:
>>> "".join("." if (i+1)%remove else c for i,c in enumerate(s))
'..c..f..i..l..o..r..u..x..'
You can use reduce following way:
>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> n=3
>>> print reduce(lambda i,x: i+x[1] if (x[0]+1)%n else i+".", enumerate(s), "")
ab.de.gh.jk.mn.pq.st.vw.yz
>>> print reduce(lambda i,x: i+"." if (x[0]+1)%n else i+x[1], enumerate(s), "")
..c..f..i..l..o..r..u..x..
Build from what you already know. You know how to find every nth character, and your result string will have all of those in it and no other character from the original string, so we can use that. We want to insert things between those, which is exactly what the str.join method does. You've already worked out that what to insert is '.' * n-1. So, you can do this:
>>> s = "abcdefghi"
>>> n = 3
>>> ('.' * (n-1)).join(s[::n])
'a..d..g'
The only trick is that you need to account for any characters after the last one that you want to leave in place. The number of those is the remainder when the highest valid index of s is divided by n - or, (len(s) - 1) % n. Which gives this slightly ugly result:
>>> ('.' * (n-1)).join(s[::n]) + '.' * ((len(s) - 1) % n)
'a..d..g..'
You probably want to use variables for the two sets of dots to help readability:
>>> dots = '.' * (n - 1)
>>> end_dots = '.' * ((len(s) - 1) % n)
>>> dots.join(s[::n]) + end_dots
'a..d..g..'
My tricky solution (I'll let you add comments):
s = 'abcdefghijklmnopqrstuvwxyz'
n = 3
single_keep_pattern = [False] * (n - 1) + [True]
keep_pattern = single_keep_pattern * ( len(s) / n + 1)
result_list = [(letter if keep else '.') for letter, keep in zip(s, keep_pattern)]
result = ''.join(result_list)
print result
gives:
..c..f..i..l..o..r..u..x..

sorts in python

I am trying to learn python and get good at algorithms. This is my first language.
for example: take "baggage" and sort into "aabeggg"
string = "baggage"
count = [0] * len(string)
for x in string:
num_value = ord(x)
count[num_value] += 1
I think the above is a start...but I'm not really sort how to go about it.
collections.Counter is a great way to solve this, but here is a way to get you a bit further in the direction you are heading
string = "baggage"
count = [0] * 256 # This should be big enough to hold counters for every 8 bit character
for x in string:
num_value = ord(x)
count[num_value] += 1
for i in range(256): # loop through all the possible 8 numbers
if count[i]:
print chr(i)*count[i]
# you can join them all back into a string like this
newstr = ''.join(chr(i)*c for i,c in enumerate(count))
Let's take a look at your code here.
string = "baggage"
count = [0] * len(string)
# count is now [0,0,0,0,0,0,0]
for x in string:
num_value = ord(x)
# ord(x) gives you the ascii number value of a character x
# So for example ord('b') = 98
count[num_value] += 1
# error here since count[98] isn't set.
Pablo gave you a quick solution. I'll write out one using a dictionary that might be more explicit.
string = "baggage"
count = {}
for c in string:
if c in count:
count[c] += 1
else:
count[c] = 1
print ''.join(count[c]*c for c in sorted(count))
Use a collections.Counter:
from collections import Counter
string = 'baggage'
c = Counter(string)
result = ''.join(c[x]*x for x in sorted(c.keys()))
It works as follows:
Counter does exactly what you were trying to achieve with count[num_value] += 1
sorted(c.keys()) gives you the characters in sorted order
c[x]*x is a string made up of c[x] copies of the char x
''.join( ... ) joins each of the resulting strings into a single one

Categories

Resources