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()
Related
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']
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.
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
How to find the digit(post number) after # and before ;; since there are other digits in the string. Finally, it produced [507, 19, 1].
Example:
post507 = "#507::empty in Q1/Q2::can list be empty::yes"
post19 = "#19::Allowable functions::empty?, first, rest::"
post1 = "#1::CS116 W2015::Welcome to first post::Thanks!"
cs116 = [post507, post1, post19]
print (search_piazza(cs116, "l")) =>[507,1,19]
(?<=#)\d+
use a lookbehind.See demo.
https://regex101.com/r/eS7gD7/33#python
import re
p = re.compile(r'(?<=#)\d+', re.IGNORECASE | re.MULTILINE)
test_str = "\"#507empty in Q1/Q2can list be emptyyes\"\n \"#19Allowable functionsempty?, first, rest\"\n \"#1CS116 W2015Welcome to first postThanks!"
re.findall(p, test_str)
iF input is in list
use
x=["#507;;empty in Q1/Q2;;can list be empty;;yes",
"#19;;Allowable functions;;empty?, first, rest;;",
"#1;;CS116 W2015;;Welcome to first post;;Thanks!"]
print [re.findall(r"(?<=#)\d+",k) for k in x]
How to find the digit(post number) in string after # and before ;;
Use re.findall along with the list_comprehension.
>>> l = ["#507;;empty in Q1/Q2;;can list be empty;;yes",
"#19;;Allowable functions;;empty?, first, rest;;",
"#1;;CS116 W2015;;Welcome to first post;;Thanks!"]
>>> [j for i in l for j in re.findall(r'#(\d+);;', i)]
['507', '19', '1']
Finally convert the resultant number to integer.
>>> [int(j) for i in l for j in re.findall(r'#(\d+);;', i)]
[507, 19, 1]
Without regex.
>>> l = ["#507;;empty in Q1/Q2;;can list be empty;;yes",
"#19;;Allowable functions;;empty?, first, rest;;",
"#1;;CS116 W2015;;Welcome to first post;;Thanks!"]
>>> for i in l:
for j in i.split(';;'):
for k in j.split('#'):
if k.isdigit():
print(k)
507
19
1
List_comprehension:
>>> [int(k) for i in l for j in i.split(';;') for k in j.split('#') if k.isdigit()]
[507, 19, 1]
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'))