python3 string "abcd" print: aababcabcd? - python

If a have a string like abcd or 1234 etc. how can I print together, the first character, then the first two characters, then the first three etc. all together?
For example for a string = 1234 I would like to print/return 1121231234 or aababcabcd
I have this code so far:
def string_splosion(str):
i = 0
while i <= len(str):
i += 1
print(str[:i])
print(string_splosion('abcd'))
But it prints/returns it in separate lines. I could write it manually as print(str[0:1], str[1:2] <...>) but how do I make python do it as I don't know how long the string is going to be?

You shouldn't use str as a variable name, because it shadows the built-in str type. You could join the sliced strings together in your loop:
def string_splosion(string):
i, result = 0, ''
while i < len(string): # < instead of <=
i += 1
result += string[:i]
return result
It's possible to shorten your code a little using str.join and range:
def string_splosion(string):
return ''.join(string[:i] for i in range(1, len(string) + 1))
or using itertools.accumulate (Python 3.2+):
import itertools
def string_splosion(string):
return ''.join(itertools.accumulate(string))
itertools.accumulate approach appears to be 2 times faster than str.join one and about 1.5 times faster than the original loop-based solution:
string_splosion_loop(abcdef): 2.3944241080715223
string_splosion_join_gen(abcdef): 2.757582983268288
string_splosion_join_lc(abcdef): 2.2879220573578865
string_splosion_itertools(abcdef): 1.1873638161591886
The code I used to time the functions is
import itertools
from timeit import timeit
string = 'abcdef'
def string_splosion_loop():
i, result = 0, ''
while i < len(string):
i += 1
result += string[:i]
return result
def string_splosion_join_gen():
return ''.join(string[:i] for i in range(1, len(string) + 1))
def string_splosion_join_lc():
# str.join performs faster when the argument is a list
return ''.join([string[:i] for i in range(1, len(string) + 1)])
def string_splosion_itertools():
return ''.join(itertools.accumulate(string))
funcs = (string_splosion_loop, string_splosion_join_gen,
string_splosion_join_lc, string_splosion_itertools)
for f in funcs:
print('{.__name__}({}): {}'.format(f, string, timeit(f)))

Just use:
"".join([s[:i] for i in range(len(s)+1)])
As #abc noted, don't use str as a variable name because it's one of the default type. see https://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange
E.g.:
>>> s = "1234"
>>> "".join([s[:i] for i in range(len(s)+1)])
'1121231234'
>>> s = "abcd"
>>> "".join([s[:i] for i in range(len(s)+1)])
'aababcabcd'
range(len(s)+1) is because of slicing, see Explain Python's slice notation:
>>> s = "1234"
>>> len(s)
4
>>> range(len(s))
[0, 1, 2, 3]
>>> s[:3]
'123'
>>> range(len(s)+1)
[0, 1, 2, 3, 4]
>>> s[:4]
'1234'
Then:
>>> s[:0]
''
>>> s[:1]
'1'
>>> s[:2]
'12'
>>> s[:3]
'123'
>>> s[:4]
'1234'
Lastly, join list([s[:1], s[:2], s[:3], s[:4]]) using "".join(list), see https://docs.python.org/2/library/string.html#string.join:
>>> list([s[:1], s[:2], s[:3], s[:4]])
['1', '12', '123', '1234']
>>> x = list([s[:1], s[:2], s[:3], s[:4]])
>>> "".join(x)
'1121231234'
>>> "-".join(x)
'1-12-123-1234'
>>> " ".join(x)
'1 12 123 1234'
To avoid extract iteration in loop, you can use range(1,len(s)+1) since s[:0] returns string of 0 length:
>>> s = "1234"
>>> "".join([s[:i] for i in range(1,len(s)+1)])
'1121231234'
>>> "".join([s[:i] for i in range(len(s)+1)])
'1121231234'

If you are using python 3 you can use this to print without a newline:
print(yourString, end="")
So your function could be:
def string_splosion(str):
for i in range(len(str)):
print(str[:i], end="")
print(string_splosion('abcd'))

Related

Extracting integers from a string and forming actual numbers from a list of these integers

I have a string bar:
bar = 'S17H10E7S5E3H2S105H90E15'
I take this string and form groups that start with the letter S:
groups = ['S' + elem for elem in bar.split('S') if elem != '']
groups
['S17H10E7', 'S5H3E2', 'S105H90E15']
Without using the mini-language RegEx, I'd like to be able to get the integer values that follow the different letters S, H, and E in these groups. To do so, I'm using:
code = 'S'
temp_num = []
for elem in groups:
start = elem.find(code)
for char in elem[start + 1: ]:
if not char.isdigit():
break
else:
temp_num.append(char)
num_tests = ','.join(temp_num)
This gives me:
print(groups)
['S17H10E7', 'S5H3E2', 'S105H90E15']
print(temp_num)
['1', '7', '5', '1', '0', '5']
print(num_tests)
1,7,5,1,0,5
How would I take these individual integers 1, 7, 5, 1, 0, and 5 and put them back together to form a list of the digits following the code S? For example:
[17, 5, 105]
UPDATE:
In addition to the accepted answer, here is another solution:
def count_numbers_after_code(string_to_read, code):
index_values = [i for i, char in enumerate(string_to_read) if char == code]
temp_1 = []
temp_2 = []
for idx in index_values:
temp_number = []
for character in string_to_read[idx + 1: ]:
if not character.isdigit():
break
else:
temp_number.append(character)
temp_1 = ''.join(temp_number)
temp_2.append(int(temp_1))
return sum(temp_2)
Would something like this work?
def get_numbers_after_letter(letter, bar):
current = True
out = []
for x in bar:
if x==letter:
out.append('')
current = True
elif x.isnumeric() and current:
out[-1] += x
elif x.isalpha() and x!=letter:
current = False
return list(map(int, out))
Output:
>>> get_numbers_after_letter('S', bar)
[17, 5, 105]
>>> get_numbers_after_letter('H', bar)
[10, 3, 90]
>>> get_numbers_after_letter('E', bar)
[7, 2, 15]
I think it's better to get all the numbers after every letter, since we're making a pass over the string anyway but if you don't want to do that, I guess this could work.
The question states that you would favour a solution without using regex ("unless absolutely necessary" from the comments)
It is not necessary of course, but as an alternative for future readers you can match S and capture 1 or more digits using (\d+) in a group that will be returned by re.findall.
import re
bar = 'S17H10E7S5E3H2S105H90E15'
print(re.findall(r"S(\d+)", bar))
Output
['17', '5', '105']

python distinguish number and string solution

I'm new to python and trying to solve the distinguish between number and string
For example :
Input: 111aa111aa
Output : Number: 111111 , String : aaaa
Here is your answer
for numbers
import re
x = '111aa111aa'
num = ''.join(re.findall(r'[\d]+',x))
for alphabets
import re
x = '111aa111aa'
alphabets = ''.join(re.findall(r'[a-zA-Z]', x))
You can use in-built functions as isdigit() and isalpha()
>>> x = '111aa111aa'
>>> number = ''.join([i for i in x if i.isdigit()])
'111111'
>>> string = ''.join([i for i in x if i.isalpha()])
'aaaa'
Or You can use regex here :
>>> x = '111aa111aa'
>>> import re
>>> numbers = ''.join(re.findall(r'\d+', x))
'111111'
>>> string = ''.join(re.findall(r'[a-zA-Z]', x))
'aaaa'
>>> my_string = '111aa111aa'
>>> ''.join(filter(str.isdigit, my_string))
'111111'
>>> ''.join(filter(str.isalpha, my_string))
'aaaa'
Try with isalpha for strings and isdigit for numbers,
In [45]: a = '111aa111aa'
In [47]: ''.join([i for i in a if i.isalpha()])
Out[47]: 'aaaa'
In [48]: ''.join([i for i in a if i.isdigit()])
Out[48]: '111111'
OR
In [18]: strings,numbers = filter(str.isalpha,a),filter(str.isdigit,a)
In [19]: print strings,numbers
aaaa 111111
As you mentioned you are new to Python, most of the presented approaches using str.join with list comprehensions or functional styles are quite sufficient. Alternatively, I present some options using dictionaries that can help organize data, starting from basic to intermediate examples with arguably increasing intricacy.
Basic Alternative
# Dictionary
d = {"Number":"", "String":""}
for char in s:
if char.isdigit():
d["Number"] += char
elif char.isalpha():
d["String"] += char
d
# {'Number': '111111', 'String': 'aaaa'}
d["Number"] # access by key
# '111111'
import collections as ct
# Default Dictionary
dd = ct.defaultdict(str)
for char in s:
if char.isdigit():
dd["Number"] += char
elif char.isalpha():
dd["String"] += char
dd

Pythonic way to parse preflib Orders with Ties files

I'm working with data from preflib.org, especially with the "Orders with Ties" format. The format looks (somewhat) like this:
1,2,{3,4,5},6
2,{3,6,4},1,5
{2,3},{4,6},{1,5}
...
I need to parse every line of these files into a list of tuples, where every tuple contains one "equivalence class" of choices. In this example:
1,2,{3,4,5},6 -> [(1,), (2,), (3,4,5), (6,)]
2,{3,6,4},1,5 -> [(2,), (3,6,4), (1), (5,)]
{2,3},{4,6},{1,5} -> [(2,3), (4,6), (1,5)]
Currently this is solved with ugly string manipulations etc. and I am pretty sure there is something more pythonic to solve this (preferably with builtins only).
EDIT: What I do currently (very hacky and ugly ...):
s = "1,2,{3,4,5},6"
classes = []
equiv_cls = None
for token in s.split(","):
if token.startswith("{"):
equiv_cls = [token[1:]]
elif token.endswith("}"):
equiv_cls.append(token[:-1])
classes.append(tuple(equiv_cls))
equiv_cls = None
elif equiv_cls is not None:
equiv_cls.append(token)
else:
classes.append(tuple(token))
You can use ast.literal_eval with some str.replace calls:
>>> from ast import literal_eval
>>> s = '1,2,{3,4,5},6'
>>> [x if isinstance(x, tuple) else (x,) for x
in literal_eval(s.replace('{', '(').replace('}', ')'))]
[(1,), (2,), (3, 4, 5), (6,)]
As #Martijn Pieters suggested you can replace the two str.replace calls with a single str.translate call:
>>> from string import maketrans
>>> table = maketrans('{}', '()')
>>> [x if isinstance(x, tuple) else (x,) for x in literal_eval(s.translate(table))]
[(1,), (2,), (3, 4, 5), (6,)]
In Python 3 you won't need any str.replace or str.translate calls calls, it fails in Python 2.7 and here is the related bug:
>>> [tuple(x) if isinstance(x, set) else (x,) for x in literal_eval(s)]
[(1,), (2,), (3, 4, 5), (6,)]
This is a very crude and silly approach but worth a look
x = "2,{3,6,4},1,5"
y = x.replace("{",'(')
y = y.replace("}",')')
y = '['+y+']'
j = []
y = eval(y)
for i in y:
typ = str(type(i))
if(typ == "<class 'int'>"):
j.append((i,))
else:
j.append(i)
print (j)
Another regex approach:
def parse_orders_with_ties(s):
s2 = re.sub(r"{([\d,]+)}|(\d+)", r"(\g<0>,)", s)
s2 = re.sub(r"[{}]", "", s2)
v = ast.literal_eval("[" + s2 + "]")
return v
For converting this data into the required list string manipulation is necessary. After basic manipulation is done the data can be converted to list using only builtins.
The following function can be a possible solution:
def convert(str_data):
b = str_data.split(',')
list_data = []
flag = 0
for each_elem in b:
if flag == 0 :
next_str = ''
if '{' in each_elem :
next_str += each_elem.split('{')[1] + ','
flag = 1
elif flag == 1 and '}' not in each_elem :
next_str += each_elem + ','
elif flag == 1 and '}' in each_elem:
next_str += each_elem.split('}')[0]
list_data.append(next_str)
flag = 0
else:
list_data.append(each_elem)
return list_data
z = convert("{2,3},{4,6},{1,5}")
z
['2,3', '4,6', '1,5']

Changing binary characters in string

I would like to convert this list:
a = [['0001', '0101'], ['1100', '0011']]
to:
a' = [['1110', '1010'],['0011','1100']]
In the second example, every character is changed to its opposite (i.e. '1' is changed to '0' and '0' is changed to '1').
The code I have tried is:
for i in a:
for j in i:
s=list(j)
for k in s:
position = s.index(k)
if k=='0':
s[position] = '1'
elif k=='1':
s[position] = '0'
''.join(s)
But it doen't work properly. What can I do?
Thanks
You can use a function that flips the bits like this:
from string import maketrans
flip_table = maketrans('01', '10')
def flip(s):
return s.translate(flip_table)
Then just call it on each item in the list like this:
>>> flip('1100')
'0011'
[["".join([str(int(not int(t))) for t in x]) for x in d] for d in a]
Example:
>>> a = [['0001', '0101'], ['1100', '0011']]
>>> a_ = [["".join([str(int(not int(t))) for t in x]) for x in d] for d in a]
>>> a_
[['1110', '1010'], ['0011', '1100']]
Using a simple list comprehension:
[[k.translate({48:'1', 49:'0'}) for k in i] for i in a]
48 is the code for "0", and 49 is the code for "1".
Demo:
>>> a = [['0001', '0101'], ['1100', '0011']]
>>> [[k.translate({48:'1', 49:'0'}) for k in i] for i in a]
[['1110', '1010'], ['0011', '1100']]
For Python 2.x:
from string import translate, maketrans
[[translate(k, maketrans('10', '01')) for k in i] for i in a]
from ast import literal_eval
import re
a = [['0001', '0101'], ['1100', '0011']]
print literal_eval(re.sub('[01]',lambda m: '0' if m.group()=='1' else '1',str(a)))
literal_eval() is said to be safer than eval()

In Python, is there an elegant way to print a list in a custom format without explicit looping?

I know you can do
print str(myList)
to get
[1, 2, 3]
and you can do
i = 0
for entry in myList:
print str(i) + ":", entry
i += 1
to get
0: 1
1: 2
2: 3
But is there a way similar to the first to get a result similar to the last?
With my limited knowledge of Python (and some help from the documentation), my best is:
print '\n'.join([str(n) + ": " + str(entry) for (n, entry) in zip(range(0,len(myList)), myList)])
It's not much less verbose, but at least I get a custom string in one (compound) statement.
Can you do better?
>>> lst = [1, 2, 3]
>>> print('\n'.join('{}: {}'.format(*k) for k in enumerate(lst)))
0: 1
1: 2
2: 3
Note: you just need to understand that list comprehension or iterating over a generator expression is explicit looping.
In python 3s print function:
lst = [1, 2, 3]
print('My list:', *lst, sep='\n- ')
Output:
My list:
- 1
- 2
- 3
Con: The sep must be a string, so you can't modify it based on which element you're printing. And you need a kind of header to do this (above it was 'My list:').
Pro: You don't have to join() a list into a string object, which might be advantageous for larger lists. And the whole thing is quite concise and readable.
l = [1, 2, 3]
print '\n'.join(['%i: %s' % (n, l[n]) for n in xrange(len(l))])
Starting from this:
>>> lst = [1, 2, 3]
>>> print('\n'.join('{}: {}'.format(*k) for k in enumerate(lst)))
0: 1
1: 2
2: 3
You can get rid of the join by passing \n as a separator to print
>>> print(*('{}: {}'.format(*k) for k in enumerate(lst)), sep="\n")
0: 1
1: 2
2: 3
Now you see you could use map, but you'll need to change the format string (yuck!)
>>> print(*(map('{0[0]}: {0[1]}'.format, enumerate(lst))), sep="\n")
0: 1
1: 2
2: 3
or pass 2 sequences to map. A separate counter and no longer enumerate lst
>>> from itertools import count
>>> print(*(map('{}: {}'.format, count(), lst)), sep="\n")
0: 1
1: 2
2: 3
>>> from itertools import starmap
>>> lst = [1, 2, 3]
>>> print('\n'.join(starmap('{}: {}'.format, enumerate(lst))))
0: 1
1: 2
2: 3
This uses itertools.starmap, which is like map, except it *s the argument into the function. The function in this case is '{}: {}'.format.
I would prefer the comprehension of SilentGhost, but starmap is a nice function to know about.
Another:
>>> lst=[10,11,12]
>>> fmt="%i: %i"
>>> for d in enumerate(lst):
... print(fmt%d)
...
0: 10
1: 11
2: 12
Yet another form:
>>> for i,j in enumerate(lst): print "%i: %i"%(i,j)
That method is nice since the individual elements in tuples produced by enumerate can be modified such as:
>>> for i,j in enumerate([3,4,5],1): print "%i^%i: %i "%(i,j,i**j)
...
1^3: 1
2^4: 16
3^5: 243
Of course, don't forget you can get a slice from this like so:
>>> for i,j in list(enumerate(lst))[1:2]: print "%i: %i"%(i,j)
...
1: 11
from time import clock
from random import sample
n = 500
myList = sample(xrange(10000),n)
#print myList
A,B,C,D = [],[],[],[]
for i in xrange(100):
t0 = clock()
ecr =( '\n'.join('{}: {}'.format(*k) for k in enumerate(myList)) )
A.append(clock()-t0)
t0 = clock()
ecr = '\n'.join(str(n) + ": " + str(entry) for (n, entry) in zip(range(0,len(myList)), myList))
B.append(clock()-t0)
t0 = clock()
ecr = '\n'.join(map(lambda x: '%s: %s' % x, enumerate(myList)))
C.append(clock()-t0)
t0 = clock()
ecr = '\n'.join('%s: %s' % x for x in enumerate(myList))
D.append(clock()-t0)
print '\n'.join(('t1 = '+str(min(A))+' '+'{:.1%}.'.format(min(A)/min(D)),
't2 = '+str(min(B))+' '+'{:.1%}.'.format(min(B)/min(D)),
't3 = '+str(min(C))+' '+'{:.1%}.'.format(min(C)/min(D)),
't4 = '+str(min(D))+' '+'{:.1%}.'.format(min(D)/min(D))))
For n=500:
150.8%.
142.7%.
110.8%.
100.0%.
For n=5000:
153.5%.
176.2%.
109.7%.
100.0%.
Oh, I see now: only the solution 3 with map() fits with the title of the question.
Take a look on pprint, The pprint module provides a capability to “pretty-print” arbitrary Python data structures in a form which can be used as input to the interpreter. If the formatted structures include objects which are not fundamental Python types, the representation may not be loadable. This may be the case if objects such as files, sockets or classes are included, as well as many other objects which are not representable as Python literals.
>>> import pprint
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
>>> stuff.insert(0, stuff[:])
>>> pp = pprint.PrettyPrinter(indent=4)
>>> pp.pprint(stuff)
[ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
'spam',
'eggs',
'lumberjack',
'knights',
'ni']
>>> pp = pprint.PrettyPrinter(width=41, compact=True)
>>> pp.pprint(stuff)
[['spam', 'eggs', 'lumberjack',
'knights', 'ni'],
'spam', 'eggs', 'lumberjack', 'knights',
'ni']
>>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
... ('parrot', ('fresh fruit',))))))))
>>> pp = pprint.PrettyPrinter(depth=6)
>>> pp.pprint(tup)
('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))

Categories