Replace elements in list based on a dictionary mapping table - python

I want to replace the elements in a list of lists based on a dictionary mapping table, and tried below:
lists_before = [['A', 'B', 'C'], ['A', 'D'], ['D', 'E']]
mapped_dictionary = {'A': 'G', 'B': 'G', 'C':'F'}
Below is the code I use:
lists_after = []
for element in lists_before:
new_element = []
for letter in element :
if letter in list(mapped_dictionary.values()):
letter = repl_dic.get(letter)
new_element.append(letter)
lists_after.append(new_element)
The output expected for lists_after is:
[['G', 'G', 'F'],['G','D'],['D','E']]
However, the output I got is still the same as lists_before.
I cannot figure out what went wrong. Could someone help me?

You can do it like this:
Input:
l = [['A', 'B', 'C'], ['A', 'D'], ['D', 'E']]
m = {'A': 'G', 'B': 'G', 'C': 'F'}
Code:
l_new = list()
for lst in l:
lst_new = list()
for ele in lst:
lst_new.append(m.get(ele, ele))
l_new.append(lst_new)
Output:
[['G', 'G', 'F'], ['G', 'D'], ['D', 'E']]
Or use a 1-liner:
[[m.get(ele, ele) for ele in lst] for lst in l]
[['G', 'G', 'F'], ['G', 'D'], ['D', 'E']]

Related

How to efficiently split a list that has a certain periodicity, into multiple lists?

For example the original list:
['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
We want to split the list into lists started with 'a' and ended with 'a', like the following:
['a','b','c','a']
['a','d','e','a']
['a','b','e','f','j','a']
['a','c','a']
The final ouput can also be a list of lists. I have tried a double for loop approach with 'a' as the condition, but this is inefficient and not pythonic.
One possible solution is using re (regex)
import re
l = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
r = [list(f"a{_}a") for _ in re.findall("(?<=a)[^a]+(?=a)", "".join(l))]
print(r)
# [['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
You can do this in one loop:
lst = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
out = [[]]
for i in lst:
if i == 'a':
out[-1].append(i)
out.append([])
out[-1].append(i)
out = out[1:] if out[-1][-1] == 'a' else out[1:-1]
Also using numpy.split:
out = [ary.tolist() + ['a'] for ary in np.split(lst, np.where(np.array(lst) == 'a')[0])[1:-1]]
Output:
[['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
Firstly you can store the indices of 'a' from the list.
oList = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
idx_a = list()
for idx, char in enumerate(oList):
if char == 'a':
idx_a.append(idx)
Then for every consecutive indices you can get the sub-list and store it in a list
ans = [oList[idx_a[x]:idx_a[x + 1] + 1] for x in range(len(idx_a))]
You can also get more such lists if you take in-between indices also.
You can do this with a single iteration and a simple state machine:
original_list = list('kabcadeabefjacab')
multiple_lists = []
for c in original_list:
if multiple_lists:
multiple_lists[-1].append(c)
if c == 'a':
multiple_lists.append([c])
if multiple_lists[-1][-1] != 'a':
multiple_lists.pop()
print(multiple_lists)
[['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
We can use str.split() to split the list once we str.join() it to a string, and then use a f-string to add back the stripped "a"s. Note that even if the list starts/ends with an "a", this the split list will have an empty string representing the substring before the split, so our unpacking logic that discards the first + last subsequences will still work as intended.
def split(data):
_, *subseqs, _ = "".join(data).split("a")
return [list(f"a{seq}a") for seq in subseqs]
Output:
>>> from pprint import pprint
>>> testdata = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
>>> pprint(split(testdata))
[['a', 'b', 'c', 'a'],
['a', 'd', 'e', 'a'],
['a', 'b', 'e', 'f', 'j', 'a'],
['a', 'c', 'a']]

How to split a list and into a tuple

If i have a list
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
and I want to split into new list without 'k', and turn it into a tuple. So I get
(['a'],['b', 'c'], ['d', 'e', 'g'])
I am thinking about first splitting them into different list by using a for loop.
new_lst = []
for element in lst:
if element != 'k':
new_ist.append(element)
This does remove all the 'k' but they are all together. I do not know how to split them into different list. To turn a list into a tuple I would need to make a list inside a list
a = [['a'],['b', 'c'], ['d', 'e', 'g']]
tuple(a) == (['a'], ['b', 'c'], ['d', 'e', 'g'])
True
So the question would be how to split the list into a list with sublist.
You are close. You can append to another list called sublist and if you find a k append sublist to new_list:
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
new_lst = []
sublist = []
for element in lst:
if element != 'k':
sublist.append(element)
else:
new_lst.append(sublist)
sublist = []
if sublist: # add the last sublist
new_lst.append(sublist)
result = tuple(new_lst)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
If you're feeling adventurous, you can also use groupby. The idea is to group elements as "k" or "non-k" and use groupby on that property:
from itertools import groupby
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
result = tuple(list(gp) for is_k, gp in groupby(lst, "k".__eq__) if not is_k)
print(result)
# (['a'], ['b', 'c'], ['d', 'e', 'g'])
Thanks #YakymPirozhenko for the simpler generator expression
tuple(list(i) for i in ''.join(lst).split('k'))
Output:
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Here's a different approach, using re.split from the re module, and map:
import re
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
tuple(map(list, re.split('k',''.join(lst))))
(['a'], ['b', 'c'], ['d', 'e', 'g'])
smallerlist = [l.split(',') for l in ','.join(lst).split('k')]
print(smallerlist)
Outputs
[['a', ''], ['', 'b', 'c', ''], ['', 'd', 'e', 'g']]
Then you could check if each sub lists contain ''
smallerlist = [' '.join(l).split() for l in smallerlist]
print(smallerlist)
Outputs
[['a'], ['b', 'c'], ['d', 'e', 'g']]
How about slicing, without appending and joining .
def isplit_list(lst, v):
while True:
try:
end = lst.index(v)
except ValueError:
break
yield lst[:end]
lst = lst[end+1:]
if len(lst):
yield lst
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g', 'k']
results = tuple(isplit_list(lst, 'k'))
Try this, works and doesn't need any imports!
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> t = []
>>> for s in ''.join(l).split('k'):
... t.append(list(s))
...
>>> t
[['a'], ['b', 'c'], ['d', 'e', 'g']]
>>> t = tuple(t)
>>> t
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Why don't you make a method which will take a list as an argument and return a tuple like so.
>>> def list_to_tuple(l):
... t = []
... for s in l:
... t.append(list(s))
... return tuple(t)
...
>>> l = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
>>> l = ''.join(l).split('k')
>>> l = list_to_tuple(l)
>>> l
(['a'], ['b', 'c'], ['d', 'e', 'g'])
Another approach using itertools
import more_itertools
lst = ['a', 'k', 'b', 'c', 'k', 'd', 'e', 'g']
print(tuple(more_itertools.split_at(lst, lambda x: x == 'k')))
gives
(['a'], ['b', 'c'], ['d', 'e', 'g'])

convert mutiple lists into a dictionary

I'm not sure if this is possible, but is there a way to combine 3 lists into a dictionary so that the list name is the key and the list of items is the value?
Example:
Inputs:
list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
list3 = ['g', 'h', 'i']
output:
dict = {
'list1': ['a', 'b', 'c'],
'list2': ['d', 'e', 'f'],
'list3': ['g', 'h', 'i']
}
thanks
if you're able to define your list in its own function,
(so they are the only variables in the local function),
you can do this:
def loc():
list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
list3 = ['g', 'h', 'i']
list_dictionary = (locals())
print(list_dictionary)
loc()
{'list1': ['a', 'b', 'c'], 'list2': ['d', 'e', 'f'], 'list3': ['g', 'h', 'i']}
Otherwise, you may need to resort to something more like this:
list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
list3 = ['g', 'h', 'i']
list_dictionary = {}
for i in ('list1', 'list2', 'list3'):
list_dictionary[i] = locals()[i]
print (list_dictionary)
{'list1': ['a', 'b', 'c'], 'list2': ['d', 'e', 'f'], 'list3': ['g', 'h', 'i']}
source: https://stackoverflow.com/a/3972978/5411817
if your variable names are repetitive, as in the example, you can compose a list of strings for the variable names:
variable_names_as_strings = []
for i in range(1,4):
variable_names_as_strings.append('list' + str(i))
Then create your dictionary:
for i in variable_names_as_strings:
list_dictionary[i] = locals()[i]
print (list_dictionary)
{'list1': ['a', 'b', 'c'], 'list2': ['d', 'e', 'f'], 'list3': ['g', 'h', 'i']}
more info on locals() (also look up globals()):
https://www.programiz.com/python-programming/methods/built-in/locals
https://docs.python.org/3.3/library/functions.html#locals
list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
list3 = ['g', 'h', 'i']
dictionary = dict()
dictionary['list1'] = list1
dictionary['list2'] = list2
dictionary['list3'] = list3
print(dictionary)
output:
{'list1': ['a', 'b', 'c'], 'list2': ['d', 'e', 'f'], 'list3': ['g', 'h', 'i']}

Sorting a list in Python without repeat previous item

Well
I have a unique combination of elements (A B C D E F)
from itertools import combinations
data = ['A', 'B', 'C', 'D', 'E', 'F'];
comb = combinations(data, 2);
d = [];
for i in comb:
d.append([i[0], i[1]]);
print d
This returns to me:
[['A', 'B'],
['A', 'C'],
['A', 'D'],
['A', 'E'],
['A', 'F'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['B', 'F'],
['C', 'D'],
['C', 'E'],
['C', 'F'],
['D', 'E'],
['D', 'F'],
['E', 'F']]
The question is, how to sort this in a way that the line N do not repeat element [0] or element [1] of line (N-1)...in a simpler way:
AB (This line can have any element)
CD (This line can't have A or B)
EF (This line can't have C or D)
AC (This line can't have E or F)
...
mylist= [['A', 'B'],
['A', 'C'],
['A', 'D'],
['A', 'E'],
['A', 'F'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['B', 'F'],
['C', 'D'],
['C', 'E'],
['C', 'F'],
['D', 'E'],
['D', 'F'],
['E', 'F']]
a=mylist[:] #this used to assign all elements to a so u have ur mylist safe
b=[]
b.append(a[0]) #this appends the first list in the list
del a[0] #now deleting appended list
while len(a)>0:
for val,i in enumerate(a):# enumerte gives index and value of list
if len(set(b[len(b)-1]).intersection(set(i)))==0: # this checks intersection so that both list should not have same elements
b.append(a[val])
del a[val]
print b
#output [['A', 'B'], ['C', 'D'], ['E', 'F'], ['A', 'C'], ['B', 'D'], ['C', 'E'], ['D', 'F'], ['A', 'E'], ['B', 'C'], ['D', 'E'], ['A', 'F'], ['B', 'E'], ['C', 'F'], ['A', 'D'], ['B', 'F']]
Using the neighborhood generator from this answer you can get the previous, current and next element in your loop, so that you can compare them. Then you can do something like this
from itertools import combinations
# Credit to Markus Jarderot for this function
def neighborhood(iterable):
iterator = iter(iterable)
prev = None
item = iterator.next() # throws StopIteration if empty.
for next in iterator:
yield (prev,item,next)
prev = item
item = next
# this can be written like this also prev,item=item,next
yield (prev,item,None)
data = ['A', 'B', 'C', 'D', 'E', 'F'];
comb = combinations(data, 2);
d = [];
for prev, item, next in neighborhood(comb):
# If prev and item both exist and neither are in the last element in d
if prev and item and not any(x in d[-1] for x in item):
d.append([item[0], item[1]])
elif item and not prev: # For the first element
d.append([item[0], item[1]])
print d
This prints
[['A', 'B'],
['C', 'D'],
['E', 'F']]
I'm aware this is probably not 100% what you need, but it should be able to get you where you want

Switch first and last elements of two lists in Python

In Python, I have two lists that either have equal number of elements (e.g. 8 and 8) or one less than the other (e.g. 7 and 8; 3 and 4):
list1 = ['A', 'B', 'C', 'D']
list2 = ['E', 'F', 'G', 'H']
or
list3 = ['A', 'B', 'C']
list4 = ['D', 'E', 'F', 'G']
I'm trying to figure out the best way to build an algorithm that will switch the last half of the first list with the first half of the last list, resulting in this, when both lists have an even number of elements:
switched_list1 = ['A', 'B', 'E', 'F']
switched_list2 = ['C', 'D', 'G', 'H']
…and this when the one of the lists has an odd number:
switched_list3 = ['A', 'D', 'E']
switched_list4 = ['B', 'C', 'F', 'G']
What's the most efficient way to build an algorithm that can switch list elements like this?
list1 = ['A', 'B', 'C']
list2 = ['D', 'E', 'F', 'G']
nlist1 = len(list1)/2
nlist2 = len(list2)/2
new1 = list1[:nlist1] + list2[:nlist2]
new2 = list1[nlist1:] + list2[nlist2:]
print new1
print new2
produces
['A', 'D', 'E']
['B', 'C', 'F', 'G']
>>> def StrangeSwitch(list1,list2):
return (list1[:len(list1)/2]+list2[:len(list2)/2],list1[len(list1)/2:]+list2[len(list2)/2:])
>>> list1 = ['A', 'B', 'C', 'D']
>>> list2 = ['E', 'F', 'G', 'H']
>>> (list1,list2)=StrangeSwitch(list1,list2)
>>> list1
['A', 'B', 'E', 'F']
>>> list2
['C', 'D', 'G', 'H']
>>> list3 = ['A', 'B', 'C']
>>> list4 = ['D', 'E', 'F', 'G']
>>> (list3,list4)=StrangeSwitch(list3,list4)
>>> list3
['A', 'B', 'C']
>>> list4
['B', 'C', 'F', 'G']
>>>
Reading the Comments by OP I would take the priviledge of proposing another approach
>>> def StrangeSwitchFast(list1,list2):
#return (list1[:len(list1)/2]+list2[:len(list2)/2],list1[len(list1)/2:]+list2[len(list2)/2:])
return (list(itertools.chain(itertools.islice(list1,0,len(list1)/2),itertools.islice(list2,0,len(list2)/2))),
list(itertools.chain(itertools.islice(list1,len(list1)/2,None),itertools.islice(list2,len(list2)/2,None))))
The above doesn't create any temporary list and if OP desires to use it as an iterator rather than a list for the downstream processing, then the list can be safely dropped from the function and can be left to return as a tuple of iterators.

Categories

Resources