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()
Related
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)
I have the following lists:
first=['a','b','c']
second=['a','a']
third=['a','b']
Is there way to compare second to first so I get FALSE,and TRUE for comparing third to first? I tried using sets but set(second).issubset(first) returns True, which is not what I need.
first=['a','b','c']
second=['a','a']
third=['a','b']
def sub_set(lst1, lst2):
tmp = lst2[:]
for i in lst1:
if i in tmp:
tmp.remove(i)
else:
return False
return True
print sub_set(second, first)
print sub_set(third, first)
output
False
True
if the order matters and the elements need to be sequential you could convert the list to a string (with join) and use this:
first=['a','b','c']
second=['a','a']
third=['a','b']
def is_sublist(sublist, reflist):
return ''.join(sublist) in ''.join(reflist)
print(is_sublist(sublist=second, reflist=first))
print(is_sublist(sublist=third, reflist=first))
You can make a comparison using slicing:
>>> first = ['a', 'b', 'c']
>>> second = ['a', 'a']
>>> third = ['a', 'b']
>>> second == first[:len(second)]
False
>>> third == first[:len(third)]
True
If order doesn't matter, you can use a count dictionary:
diffs = {a : second.count(a) - first.count(a) for a in second}
diffs_list = list(diffs1.values())
is_subset = len(diffs_list) == diffs_list.count(0)
That returns True for third, and False for second.
This simply counts the occurrence of each element of the subset in the superset, computes the difference of each count, then verifies that all differences are 0.
lets say I have an array "array_1" with these items:
A b A c
I want to get a new array "array_2" which looks like this:
b A c A
I tried this:
array_1 = ['A','b','A','c' ]
array_2 = []
for item in array_1:
if array_1[array_1.index(item)] == array_1[array_1.index(item)].upper():
array_2.append(array_1[array_1.index(item)+1]+array_1[array_1.index(item)])
The problem: The result looks like this:
b A b A
Does anyone know how to fix this? This would be really great!
Thanks, Nico.
It's because you have 2 'A' in your array. In both case for the 'A',
array_1[array_1.index(item)+1
will equal 'b' because the index method return the first index of 'A'.
To correct this behavior; i suggest to use an integer you increment for each item. In that cas you'll retrieve the n-th item of the array and your program wont return twice the same 'A'.
Responding to your comment, let's take back your code and add the integer:
array_1 = ['A','b','A','c' ]
array_2 = []
i = 0
for item in array_1:
if array_1[i] == array_1[i].upper():
array_2.append(array_1[i+1]+array_1[i])
i = i + 1
In that case, it works but be careful, you need to add an if statement in the case the last item of your array is an 'A' for example => array_1[i+1] won't exist.
I think that simple flat list is the wrong data structure for the job if each lower case letter is paired with the consecutive upper case letter. If would turn it into a list of two-tuples i.e.:
['A', 'b', 'A', 'c'] becomes [('A', 'b'), ('A', 'c')]
Then if you are looping through the items in the list:
for item in list:
print(item[0]) # prints 'A'
print(item[1]) # prints 'b' (for first item)
To do this:
input_list = ['A', 'b', 'A', 'c']
output_list = []
i = 0;
while i < len(input_list):
output_list.append((input_list[i], input_list[i+1]))
i = i + 2;
Then you can swap the order of the upper case letters and the lower case letters really easily using a list comprehension:
swapped = [(item[1], item[0]) for item in list)]
Edit:
As you might have more than one lower case letter for each upper case letter you could use a list for each group, and then have a list of these groups.
def group_items(input_list):
output_list = []
current_group = []
while not empty(input_list):
current_item = input_list.pop(0)
if current_item == current_item.upper():
# Upper case letter, so start a new group
output_list.append(current_group)
current_group = []
current_group.append(current_item)
Then you can reverse each of the internal lists really easily:
[reversed(group) for group in group_items(input_list)]
According to your last comment, you can get what you want using this
array_1 = "SMITH Mike SMITH Judy".split()
surnames = array_1[1::2]
names = array_1[0::2]
print array_1
array_1[0::2] = surnames
array_1[1::2] = names
print array_1
You get:
['SMITH', 'Mike', 'SMITH', 'Judy']
['Mike', 'SMITH', 'Judy', 'SMITH']
If I understood your question correctly, then you can do this:
It will work for any length of array.
array_1 = ['A','b','A','c' ]
array_2 = []
for index,itm in enumerate(array_1):
if index % 2 == 0:
array_2.append(array_1[index+1])
array_2.append(array_1[index])
print array_2
Output:
['b', 'A', 'c', 'A']
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'
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