for loop to concatenate strings - python

I need to concatenate strings in the list and add the integers to a sum; of course, I intend to change it to other data types later - thanks so much for all your kind responses
l = ['magical unicorns', 19, 'hello', 98.98, 'world']
comb_str = ''
comb_int = 0
for i in l:
if type(i) is 'str':
comb_str = comb_str + 'i'
elif type(i) is 'int':
comb_int += i
else:
pass
print comb_str
print comb_int
I am just getting the '0' output that was initialized in the beginning as if it skipped over the for loop :)

Taking your statements literally (that you only want integers, not numerics) the entire program comes down to two function calls with filtered versions of the list
>>> l = ['magical unicorns', 19, 'hello', 98.98, 'world']
>>> ''.join([s for s in l if isinstance(s,str)])
'magical unicornshelloworld'
>>> sum([i for i in l if isinstance(i,int)])
19
>>

You can try this out:
l = ['magical unicorns', 19, 'hello', 98.98, 'world']
l1 = [g for g in l if type(g)==int]
l2 = [g for g in l if type(g)==str]
print(sum(l1))
print(''.join(l2))
This will print your desired outcome.

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']

how to split after each word and get the following string in an organized way?

Given the following string:
'hello0192239world0912903spam209394'
I would like to be able to split the above string into this
hello, 0192239, world, 0912903, spam, 209394
and ideally end with a list:
[hello, 0192239], [world, 0912903], [spam, 209394]
But I just don't know how to go about even the first step, splitting by word x number. I know there's the split method and something called regex but I don't know how to use it and even if it's the right thing to use
Try this:
>>> lst = re.split('(\d+)','hello0192239world0912903spam209394')
>>> list(zip(lst[::2],lst[1::2]))
[('hello', '0192239'), ('world', '0912903'), ('spam', '209394')]
>>> lst = re.split('(\d+)','09182hello2349283world892')
>>> list(zip(lst[::2],lst[1::2]))
[('', '09182'), ('hello', '2349283'), ('world', '892')]
# as a list
>>> list(map(list,zip(lst[::2],lst[1::2])))
[['', '09182'], ['hello', '2349283'], ['world', '892']]
See below. The idea is to maintain a 'mode' and flip mode every time you switch from digit to char or the other way around.
data = 'hello0192239world0912903spam209394'
A = 'A'
D = 'D'
mode = D if data[0].isdigit() else A
holder = []
tmp = []
for x in data:
if mode == A:
is_digit = x.isdigit()
if is_digit:
mode = D
holder.append(''.join(tmp))
tmp = [x]
continue
else:
is_char = not x.isdigit()
if is_char:
mode = A
holder.append(''.join(tmp))
tmp = [x]
continue
tmp.append(x)
holder.append(''.join(tmp))
print(holder)
output
['hello', '0192239', 'world', '0912903', 'spam', '209394']

How to write faster Python code?

My code
with open('data1.txt','r') as f:
lst = [int(line) for line in f]
l1=lst[::3]
l2=lst[1::3]
l3=lst[2::3]
print len(l1)
print len(l2)
print len(l3)
b = []
for i in range(3200000):
b.append(i+1)
print len(b)
mapping = dict(zip(l1, b))
matches = [mapping[value] for value in l2 if value not in mapping]
print matches
My aim here is two compare lists,they are expected to have same elements.
Works fine
3200000
3200000
3200000
3200000
[]
But problem is that the code is very slow and I will have more calculations later.How to improve this?
My python
Python 2.7.6
This will not be as efficient regarding to memory but VERY efficient regarding execution speed.
It seems like you do not use l3. diff will have everything not contained in both lists.
import itertools
with open('data1.txt','r') as f:
lines = map(int, f)
l1 = itertools.islice(lines, 0, None, 3)
l2 = itertools.islice(lines, 1, None, 3)
diff = set(l1) ^ set(l2)
First, I don't see how that can work:
[mapping[value] for value in l2 if value not in mapping]
I suppose the value is always in mapping and the array is always empty. It should throw an error otherwise since the key will not be found.
Then, try something like this, with no useless memory allocation:
mapping = {}
l2 = []
with open('data1.txt','r') as f:
for i,line in enumerate(f):
v = int(line)
if i % 3 == 0:
mapping[v] = i+1
elif i % 3 == 1:
l2.append(v)
matches = [mapping[value] for value in l2 if value not in mapping] # ??
print(matches)

python3 string "abcd" print: aababcabcd?

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'))

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()

Categories