Python Concatenating Strings - python

1 def add(i):
2 return '\''+i+'\''
3 a = ['a', 'b']
4 print " or ".join([add(i) for i in a])
OUTPUT: 'a' or 'b'
I am not sure if the above is the best way (esp the add function).
Is there a better way to achieve what I am trying to do?

You can use repr:
>>> a = ['a', 'b']
>>> print " or ".join(repr(i) for i in a)
'a' or 'b'

Related

How to create a list conditionally?

I have a following problem. I would like to form a list a conditionally.
Lets say I have a variable add_string and if it's True then
a = ["a","b","Added String","c"]
Else
a = ["a","b","c"]
what's the best way to do that? I can do that in the following manner
a = ["a","b","c"]
if add_string:
a.insert(2,"Added String")
But that's not ideal since list a might change in future and I will have to change the index in the insert function. Also I have a condition — this added string should always follow after "b". Another solution is to search for "b" in the list and then insert after that, but that adds complexity and it's ugly.
Ideally I thought it should be something like
a = ["a","b",if add_string then "Added String","c"]
a = ["a","b"] + (["Added String"] if add_string else []) + ["c"]
If you know all the values when you create a, you could do something like this:
add_string = True
a = ['a', 'b'] + (['Added String'] if add_string else []) + ['c']
Output:
['a', 'b', 'Added String', 'c']
If you don't know the values in a, you could use index to find the location of 'b' in a, and insert the string after that:
a = ["a","b","c"]
add_string = True
if add_string:
a.insert(a.index("b")+1,"Added String")
print(a)
Output:
['a', 'b', 'Added String', 'c']
You could set unwanted values to a known value (such as None) and then remove them using list comprehension:
add_string = False # Could be True
unfiltered_list = ["a","b","Added String" if add_string else None,"c"]
a = [x for x in unfiltered_list if x is not None]
print(a)

Simple python string concatenation

I have following test,
def test_strings_concatenation(self):
dict = ['a', 'b', 'c']
dict_as_string = " ".join(dict)
expected = 'a b c'
assert dict_as_string is expected
and I want to get dict exactly, (identical to) expected. Is there any way to get this?
To begin with, never use pre-defined constants like dict as variable names as #Amadan pointed out, also ['a', 'b', 'c'] is a list, and not a dictionary, (which is a container to hold key-value pairs e.g. {"a":"b"}.
Also you would want to check for == since you want the list to be concatenated to a string, and not is, since is checks if two object refers to the same location of memory as #TomaszBartkowiak pointed out , like below
In [21]: a = 1
In [22]: b = a
In [23]: a is b
Out[23]: True
In [24]: li = ['a', 'b', 'c']
In [25]: s = ' '.join(li)
In [26]: s is li
Out[26]: False
Hence the code will change to
def test_strings_concatenation():
#Define list and concatenate it
li = ['a', 'b', 'c']
li_as_string = " ".join(li)
expected = 'a b c'
#Check for string equality
assert li_as_string == expected
test_strings_concatenation()

Way to accomplish task using list comphrehension

Is there a way to accomplish the following using a list comprehension? Or is there a more Pythonic way of accomplishing this?
count = 0
x = 'uewoiquewqoiuinkcnsjk'
for letter in x:
if letter in ['a', 'e', 'i', 'o', 'u']:
count += 1
Just trying to learn the best programming practices?
Since in generates a True or False and True and False can reliably be used as 1 and 0 you can use sum with a generator:
sum(c in 'aeiou' for c in x)
Or filter + len:
len(filter(lambda c: c in 'aeiou', x))
A great way to do the opposite is to use str.translate to delete characters in the string:
>>> x.translate(None, 'aeiou')
wqwqnkcnsjk
So then you can do:
len(x)-len(x.translate(None, 'aeiou'))
In all cases, the answer is 10
Use the combination of list_comprehension and len function.
>>> x = 'uewoiquewqoiuinkcnsjk'
>>> len([i for i in x if i in 'aeiou'])
10
>>>

How to maintain a strict alternating pattern of item "types" in a list?

Given a list of strings, where each string is in the format "A - something" or "B - somethingelse", and list items mostly alternate between pieces of "A" data and "B" data, how can irregularities be removed?
Irregularities being any sequence that breaks the A B pattern.
If there are multiple A's, the next B should also be removed.
If there are multiple B's, the preceding A should also be removed.
After removal of these invalid sequnces, list order should be kept.
Example: A B A B A A B A B A B A B A B B A B A B A A B B A B A B
In this case, AAB (see rule 2), ABB (see rule 3) and AABB should be removed.
I'll give it a try with regexp returning indexes of sequences to be removed
>>> import re
>>> data = 'ABABAABABABABABBABABAABBABAB'
>>> [(m.start(0), m.end(0)) for m in re.finditer('(AA+B+)|(ABB+)', data)]
[(4, 7), (13, 16), (20, 24)]
or result of stripping
>>> re.sub('(AA+B+)|(ABB+)', '', data)
ABABABABABABABABAB
The drunk-on-itertools solution:
>>> s = 'ABABAABABABABABBABABAABBABAB'
>>> from itertools import groupby, takewhile, islice, repeat, chain
>>> groups = (list(g) for k,g in groupby(s))
>>> pairs = takewhile(bool, (list(islice(groups, 2)) for _ in repeat(None)))
>>> kept_pairs = (p for p in pairs if len(p[0]) == len(p[1]) == 1)
>>> final = list(chain(*chain(*kept_pairs)))
>>> final
['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
(Unfortunately I'm now in no shape to think about corner cases and trailing As etc..)
I'd write it as a generator. Repeat:
read as many A's as possible,
read as many B's as possible,
if you've read exactly 1 A and 1 B, yield them; otherwise ignore and proceed.
Also this needs an additional special case in case you want to allow the input to end with an A.
Using itertools.groupby:
from itertools import groupby
def solve(strs):
drop_next = False
ans = []
for k, g in groupby(strs):
lis = list(g)
if drop_next:
#if True then don't append the current set to `ans`
drop_next = False
elif len(lis) > 1 and k == 'A':
#if current group contains more than 1 'A' then skip the next set of 'B'
drop_next = True
elif len(lis) > 1 and k == 'B':
#if current group contains more than 1 'B' then pop the last appended item
if ans:
ans.pop(-1)
else:
ans.append(k)
return ''.join(ans)
strs = 'ABABAABABABABABBABABAABBABAB'
print solve(strs)
#ABABABABABABABABAB

How can I do 'a' + 1 #=> 'b' in python?

I'm working on a project need this functionality very frequently
'b' + 1 #=> 'a' and 'b' - 1 #=> 'a'
Now my solution is very tedious :
str(unichr((ord('b')+ 1)))
is there a more elegant way to do this?
str(unichr(c)) can be replaced with just chr(c).
Simplified version:
chr(ord('b') + 1)
define your own function:
In [103]: def func(c,n):
return chr(ord(c)+n)
.....:
In [105]: func('a',-1)
Out[105]: '`'
In [106]: func('b',-1)
Out[106]: 'a'
In [107]: func('c',2)
Out[107]: 'e'
Python is strongly typed and considerer strings and ints are different, and won't convert one to another implicitly.
However, you code can probably be simplified to
chr(ord('b') + 1)
If you use it a lot, put it in a function, and don't worry about it any more :
def incr_char(c, n):
return chr(ord(c) + n)
Try this instead:
>>> import string
>>> string.letters[string.letters.index('a')+1]
'b'
Just for Ashwini:
>>> string.letters[string.letters.index('a')-1]
'Z'
You can do something like:
class char(unicode):
def __add__(self, x):
return char(unichr(ord(self) + x))
print char('a') + 1 # b

Categories

Resources