merge complex matrix with python - python

I have a complex matrix that looks like this:
[[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
I want to turn it into this:
['x', '1a', '2b', '3c', '4d'],
['y', '5e', '6f', '7g', '8h']
I'm busting my head but not managing to achieve the result. Also, even though I only have two groups of nested 5-items long lists, in theory I want to solve this for an infinite number of groups of the same size.

You can use a dict here:
>>> from operator import add
>>> lis = [[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
>>> dic = {}
for item in lis:
for x in item:
k, v = x[0], x[1:]
if k in dic:
dic[k] = map(add, dic[k], v)
else:
dic[k] = v
...
>>> dic
{'y': ['5e', '6f', '7g', '8h'], 'x': ['1a', '2b', '3c', '4d']}
#list of lists
>>> [[k] + v for k, v in dic.iteritems()]
[['y', '5e', '6f', '7g', '8h'], ['x', '1a', '2b', '3c', '4d']]
Another solution using zip, reduce and a list comprehension:
>>> from operator import add
>>> def func(x, y):
... return map(add, x, y[1:])
>>> [[item[0][0]] + reduce(func, item[1:], item[0][1:]) for item in zip(*lis)]
[['x', '1a', '2b', '3c', '4d'], ['y', '5e', '6f', '7g', '8h']]

Here's a "fun" solution. Since you did not provide any information about your array's structure, I assumed the easiest variant:
import numpy
a = numpy.array([[
['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[
['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h']]],
dtype=numpy.object)
res = a[0].copy()
for chunk in a[1:]:
res[:,1:] += chunk[:,1:]
print(res)

Related

How to format list in python

So I am trying to format a list for this:
['w', 'e', '5', 'p', '4', '7', '2', 'w']
to this:
we5p472w
Any idea how to do this?
NOTE: this is a LIST, not a STRING
Use the join() method:
l = ['w', 'e', '5', 'p', '4', '7', '2', 'w']
print (''.join(l))
Outut:
we5p472w
You can use any expression to join your list elements:
print (' '.join(l))
Output:
w e 5 p 4 7 2 w
Code:
myList = ['w', 'e', '5', 'p', '4', '7', '2', 'w']
myString = "".join(myList)
print(myString)
Output:
$ we5p472w
list1 = ['w', 'e', '5', 'p', '4', '7', '2', 'w']
print("".join(list1))
returns we5p472w
check https://www.geeksforgeeks.org/join-function-python/ for a more detail explanation and more examples

How to combine 'like' elements within nested list?

I have 3 nested lists:
STEP = [['S', '1', 'B', '3'], ['S', '3', 'B', '11'], ['S', '5', 'B', '12'], ['S', '4', 'B', '13'], ['S', '2', 'B', '14']]
TRANSITION = [['T', '2', 'B', '4'], ['T', '7', 'B', '4'], ['T', '3', 'S', '4'], ['T', '5', 'S', '5'], ['T', '1', 'S', '2'], ['T', '8', 'S', '2'], ['T', '6', 'S', '1'], ['T', '9', 'S', '2'], ['T', '4', 'S', '1'], ['T', '10', 'S', '1']]
BRANCH = [['B', '3', 'T', '1'], ['B', '3', 'T', '7'], ['B', '4', 'S', '3'], ['B', '11', 'T', '3'], ['B', '11', 'T', '5'], ['B', '12', 'T', '6'], ['B', '12', 'T', '8'], ['B', '13', 'T', '4'], ['B', '13', 'T', '9'], ['B', '14', 'T', '2'], ['B', '14', 'T', '10']]
Each element holds information as such:
# Example
STEP[0] = ['S', '1', 'B', '3']
Where:
'S' is the STEP type
'1' is the STEP number id
'B' is the linked BRANCH type
'3' is the linked BRANCH number id
Starting from a STEP the data is all linked, so using the linked reference you can find the next element and the next until another STEP is reached.
This is some parameters of the data:
STEPS are connected to single BRANCHES
BRANCHES are connected to one or more TRANSITIONS
TRANSITIONS can be connected to a single BRANCH or STEP
The BRANCH data can have a fork where a single BRANCH id has one or more options for TRANSITIONS.
I would like to combine these forks to the same `BRANCH' id, ie:
# BRANCH[0] and BRANCH[1] both have an id of '3'
# therefore, need to be combined
BRANCH[0] = ['B', '3', 'T', ['1', '7']]
This should be done to create a new list that combines all 'like' BRANCHES.
My attempt thus far (did not get very far):
for i in B:
if i[1] == B['all except current i'][1]
# append the branch id and the two transitions
I'm pretty sure there are easier ways, but based on your example, you can try :
BRANCH = [['B', '3', 'T', '1'], ['B', '3', 'T', '7'], ['B', '4', 'S', '3'], ['B', '11', 'T', '3'], ['B', '11', 'T', '5'], ['B', '12', 'T', '6'], ['B', '12', 'T', '8'], ['B', '13', 'T', '4'], ['B', '13', 'T', '9'], ['B', '14', 'T', '2'], ['B', '14', 'T', '10']]
tmp = {}
final = []
for x in BRANCH:
if not f"{x[0]}-{x[1]}" in tmp:
tmp[f"{x[0]}-{x[1]}"] = [x[3]]
else:
tmp[f"{x[0]}-{x[1]}"].append(x[3])
for k, v in tmp.items():
one, two = k.split("-")
for x in BRANCH:
if x[0] == one and x[1] == two:
if not [one, two, x[2], v] in final:
final.append([one, two, x[2], v])
print(final)
[['B', '3', 'T', ['1', '7']], ['B', '4', 'S', ['3']], ['B', '11', 'T', ['3', '5']], ['B', '12', 'T', ['6', '8']], ['B', '13', 'T', ['4', '9']], ['B', '14', 'T', ['2', '10']]]
Demo
You can use a test for similarity of the branches and then loop over the branches checking similarity. The rest is just guarding against duplicates and massaging the data to a list of lists. I did randomize the data and add another item to check that it wouldn't choke on more than a pair of similar branches.
# Check similarity (first three fields equal).
def similar_p(one, two):
for item in range(len(one) - 1):
if one[item] != two[item]:
return False
return True
# Data. Works sorted and not.
branches = [
['B', '14', 'T', '2'],
['B', '12', 'T', '6'],
['B', '14', 'T', '10'],
['B', '13', 'T', '4'],
['B', '3', 'T', '9'],
['B', '12', 'T', '8'],
['B', '13', 'T', '9'],
['B', '3', 'T', '7'],
['B', '4', 'S', '3'],
['B', '11', 'T', '5'],
['B', '3', 'T', '1'],
['B', '11', 'T', '3'],
]
merge_dict = {}
# Loop over branches. Uncomment print statements to watch the action.
for i in range(len(branches)):
# print('check for similars to branch {}'.format(branches[i]))
# try/except to ensure the dictionary item is actually there.
try:
# print(merge_dict[tuple(branches[i][0:3])])
if branches[i][3] not in merge_dict[tuple(branches[i][0:3])]:
merge_dict[tuple(branches[i][0:3])].append(branches[i][3])
# print('initial appending to branch {}'.format(branches[i]))
except (KeyError):
merge_dict[tuple(branches[i][0:3])] = [branches[i][3]]
# print('starting branch {}'.format(branches[i]))
for j in range((i + 1), len(branches), 1):
if similar_p(branches[i], branches[j]):
if branches[j][3] not in merge_dict[tuple(branches[i][0:3])]:
merge_dict[tuple(branches[i][0:3])].append(branches[j][3])
# print('appending similar branch {} to branch {}'.format(branches[j], branches[i]))
merged = list()
# Massage into a list. Sorting is on you, kid.
for k,v in merge_dict.items():
if len(v) == 1:
merged.append([*k, *v])
else:
merged.append([*k, v])
print(merged)
Output:
[['B', '14', 'T', ['2', '10']], ['B', '12', 'T', ['6', '8']], ['B', '13', 'T', ['4', '9']], ['B', '3', 'T', ['9', '7', '1']], ['B', '4', 'S', '3'], ['B', '11', 'T', ['5', '3']]]

Python: Comparing value overlap between keys in a dictionary

I have a dict like this:
dict = defaultdict(list, {'a': [['1', '2', 'A', 'cat'],
['1', '3', 'A', 'dog']],
'b': [['1', '2', 'A', 'cat'],
['1', '3', 'A', 'dog']],
'c': [['1', '2', 'A', 'cat'],
['2', '2', 'A', 'snake'],
['2', '2', 'A', 'bird']]}
I'd like to get all pairwise comparisons for overlapping values using the full list for each value. (Every position in the value list must match for it to be considered a match between keys)
Since a and b share ['1', '3', 'A', 'dog'] and c doesn't, a/b: ['1', '3', 'A', 'dog'].
a, b, c, all share ['1', '2', 'A', 'cat'], a/b/c: ['1', '2', 'A', 'cat'].
Only c has ['2', '2', 'A', 'snake'], so c: ['2', '2', 'A', 'snake']
Preferred output is a dictionary combining the above, something like
combine_dict = {'a/b': ['1', '3', 'A', 'dog'], 'a/b/c': ['1', '2', 'A', 'cat'], 'c': [['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}
You can use collections.defaultdict:
import collections
d = {'a': [['1', '2', 'A', 'cat'], ['1', '3', 'A', 'dog']], 'b': [['1', '2', 'A', 'cat'], ['1', '3', 'A', 'dog']], 'c': [['1', '2', 'A', 'cat'], ['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}
new_d = collections.defaultdict(list)
for a, b in d.items():
for i in b:
new_d[tuple(i)].append(a)
new_r = collections.defaultdict(list)
for a, b in new_d.items():
new_r['/'.join(b)].append(list(a))
new_result = {a:b[0] if len(b) == 1 else b for a, b in new_r.items()}
Output:
{'a/b/c': ['1', '2', 'A', 'cat'], 'a/b': ['1', '3', 'A', 'dog'], 'c': [['2', '2', 'A', 'snake'], ['2', '2', 'A', 'bird']]}

Convert flat list to dictionary with keys at regular intervals [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a list containing a string and lists. I should show you;
list_x = ['a', ['j', '1', 'x'], ['k', '2', 'y'], ['a', '3', 'hj'],
'd', ['b', '4', 'df'], ['c', '5', 'er'], ['d', '6', 'ty'],
'g', ['e', '7', 'hj'], ['f', '8', 'bv'], ['g', '9', 'sad'],
'j', ['h', '10', 'kj'], ['i', '11', 'nbv'], ['c', '12', 'uy'],
'n', ['d', '13', 'ipoas'], ['e', '14', 'fg'], ['f', '15', 'as'],
'r', ['g', '16', 'dsad'], ['h', '17', 'fdgdfg'], ['i', '18', 'retrt'],
'u', ['j', '19', 'qwe'], ['k', '20', 'ytgf'], ['n', '21', 'asmz']]
And I want a dict from this list like this;
dict_x = {'a': [['j', '1', 'x'], ['k', '2', 'y'], ['a', '3', 'hj']],
'd': [['b', '4', 'df'], ['c', '5', 'er'], ['d', '6', 'ty']],
'g': [['e', '7', 'hj'], ['f', '8', 'bv'], ['g', '9', 'sad']],
'j': [['h', '10', 'kj'], ['i', '11', 'nbv'], ['c', '12', 'uy']],
'n': [['d', '13', 'ipoas'], ['e', '14', 'fg'], ['f', '15', 'as']],
'r': [['g', '16', 'dsad'], ['h', '17', 'fdgdfg'], ['i', '18', 'retrt']],
'u': [['j', '19', 'qwe'], ['k', '20', 'ytgf'], ['n', '21', 'asmz']]}
Here's a straightforward solution with a simple loop:
dict_x = {}
for value in list_x:
if isinstance(value, str):
dict_x[value] = current_list = []
else:
current_list.append(value)
Basically, if the value is a string then a new empty list is added to the dict, and if it's a list, it's appended to the previous list.
Here is one way using a dictionary comprehension and a generator expression combined with * unpacking.
res = {i: j for i, *j in (list_x[i:i + 4] for i in range(0, len(list_x), 4))}
# {'a': [['j', '1', 'x'], ['k', '2', 'y'], ['a', '3', 'hj']],
# 'd': [['b', '4', 'df'], ['c', '5', 'er'], ['d', '6', 'ty']],
# 'g': [['e', '7', 'hj'], ['f', '8', 'bv'], ['g', '9', 'sad']],
# 'j': [['h', '10', 'kj'], ['i', '11', 'nbv'], ['c', '12', 'uy']],
# 'n': [['d', '13', 'ipoas'], ['e', '14', 'fg'], ['f', '15', 'as']],
# 'r': [['g', '16', 'dsad'], ['h', '17', 'fdgdfg'], ['i', '18', 'retrt']],
# 'u': [['j', '19', 'qwe'], ['k', '20', 'ytgf'], ['n', '21', 'asmz']]}
Alternatively, as #chrisz suggests, you can use zip:
res = {i: j for i, *j in zip(*(list_x[i::4] for i in range(4)))}

How do I check whether a variable was changed?

Say I have two lists
[['1', '2', '1', '3', '1', '3'], ['A', 'G', 'T', 'T', 'T', 'G']]
In this case each index matches the number on the left with the letter on the right, so 1 : A, and 2 : G and so on. I want to see if AT LEAST one number on the left changes mapping. So, I want to know if ANY number changes mapping. So if 1 : A changes to 1 : T, I would have True returned.
You can create a dictionary:
s = [['1', '2', '1', '3', '1', '3'], ['A', 'G', 'T', 'T', 'T', 'G']]
new_s = {b:a for a, b in zip(*s)}
final_vals = [a for a, b in new_s.items() if any(d == b for c, d in new_s.items() if c != a)]
Output:
['A', 'T']
Actually perform the assignments in a dictionary, stop whenever one changes an existing entry.
def check_overwrite(keys, values):
d = {}
for k,v in zip(keys, values):
if d.setdefault(k, v) != v:
return True
return False
print check_overwrite(['1', '2', '1', '3', '1', '3'], ['A', 'G', 'T', 'T', 'T', 'G'])
If you want to know if it's not only changed but what changed this (stolen from above) should help
>>> numbers = ['1', '2', '1', '3', '1', '3']
>>> letters = ['A', 'G', 'T', 'T', 'T', 'G']
>>> def check_overwrite(keys, values):
... d = {}
... overlap = {}
... for k,v in zip(keys, values):
... if d.setdefault(k, v) != v:
... overlap[k] = v
... return overlap
...
>>> check_overwrite(numbers, letters)
{'1': 'T', '3': 'G'}

Categories

Resources