How to combine 'like' elements within nested list? - python

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']]]

Related

Merge every certain number of items in a list

I have a list like this
items= ['e', '4', 'e', 'e', '4', '5', '4', '8', 'a', '8', '6', 'd', '8', 'a', 'e', '1', 'b', '6', '2', '1', '6', 'a', 'a', 'a', '2', 'b', 'd', '6', '7', '7', '9', '2']
I want to edit the list so that every 4 items in the list get merged like this
items=['e4ee', '4548', 'a86d', '8ae1', 'b621', '6aaa', '2bd6', '7792']
Edit: My mistake for wording. By not creating a new list I meant by putting the arranged elements into a separate list like this
items = ['e', '4', 'e', 'e', ...
items2 = ['e4ee', '4548', ...
You could do it like this although this does create a new list:
items = ['e', '4', 'e', 'e', '4', '5', '4', '8', 'a', '8', '6', 'd', '8', 'a', 'e', '1', 'b', '6', '2', '1', '6', 'a', 'a', 'a', '2', 'b', 'd', '6', '7', '7', '9', '2']
items = [''.join(items[i:i+4]) for i in range(0, len(items), 4)]
print(items)
Output:
['e4ee', '4548', 'a86d', '8ae1', 'b621', '6aaa', '2bd6', '7792']
If you absolutely do not want to create a new list (as stated):
result_len = len(items) // 4
for i in range(result_len):
j = (i*4)
items[i] = ''.join(items[j:(j+4)])
for i in range(len(items) - 1, result_len - 1, -1):
del items[i]
Does exactly len(items) iterations and never creates a new list.
The first loop updates the first result_len items in the list to the desired values. The second one deletes the rest of the items from it.
EDIT: Whoops, had a bug there. Now it should be correct.

Issue with single line nested for loop in Python

I have data that exports in a string
output = '012345678910abcdefghijkl'
cleaned_output = [output[index:index + 4] for index in range(0, len(output), 4)]
cleaned_output = [cleaned_output[i][item] for i in range(0, len(cleaned_output)) for item in range(0,len(cleaned_output[i]))]
Which returns:
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
However, I am looking to return the below, any ideas on where I am going wrong?
[['0', '1', '2', '3'], ['4', '5', '6', '7'], ['8', '9', '1', '0'], ['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]
You should just split your input into chunks of 4 and then convert them directly to lists:
cleaned_output = [list(output[i:i+4]) for i in range(0, len(output), 4)]
Output:
[['0', '1', '2', '3'], ['4', '5', '6', '7'], ['8', '9', '1', '0'], ['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]

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 copy common elements in sublist?

I am reading a text file which contains some numbers and letters in each row.
The first number of each row is a unique ID, and I want to copy all the same IDs into a separate list.
For example, if my list after reading the file is something like this:
[
['507', 'W', '1000', '1'],
['1', 'M', '6', '2'],
['1', 'W', '1400', '3'],
['1', 'M', '8', '8'],
['1', 'T', '101', '10'],
['507', 'M', '4', '12'],
['1', 'W', '1700', '15'],
['1', 'M', '7', '16'],
['507', 'M', '8', '20'],
...
]
The expected output should be the following:
[
['507', 'W', '1000', '1','507', 'M', '4', '12','507', 'M', '8', '20'],
['1', 'M', '6', '2','1', 'M', '8', '8','1', 'T', '101', '10','1', 'W', '1700', '15','1', 'M', '7', '16']
...
]
and so on for all other unique IDs in file.
All the rows starting with "507" should be stored in a different list and the rows starting with "1" stored in another and so forth.
My current code:
import operator
fileName = '/home/salman/Desktop/input.txt'
lineList = []
first_number = []
common_number = []
with open(fileName) as f:
for line in f:
lineList = f.readlines()
lineList.append(line)
lineList = [line.rstrip('\n') for line in open(fileName)]
first_number = [i.split()[0] for i in lineList]
print("Rows in list:" + str(lineList))
print("First number in list : " + str(first_number))
common_number = list(set(first_number))
print("Common Numbers in first number list : "+ str(common_number))
print("Repeated value and their index's are :")
This is my attempt. First please read this document on groupby: https://docs.python.org/3/library/itertools.html#itertools.groupby and how it is important to order your sequence first. Here your key is the first element of the lists so I order by that. sorted: https://docs.python.org/3/howto/sorting.html
Flatten a list of lists: How to make a flat list out of list of lists?
Explanation: Sort the elements so consecutive entries have the same key i.e. first element. When that key changes, then we know that all items with the previous key have been exhausted. So basically we need to find where the first element of consecutive entries change. That's what the groupby object provide. It gives a tuple of (key, group) where key would be the first element that identifies each group and group would be a generator of all lists with the same key (so a generator which really is just a list of lists). We unpack them and flatten them.
import itertools
lst = [
['507', 'W', '1000', '1'],
['1', 'M', '6', '2'],
['1', 'W', '1400', '3'],
['1', 'M', '8', '8'],
['1', 'T', '101', '10'],
['507', 'M', '4', '12'],
['1', 'W', '1700', '15'],
['1', 'M', '7', '16'],
['507', 'M', '8', '20']
]
lst = sorted(lst, key=lambda x: x[0])
groups = itertools.groupby(lst, key=lambda x: x[0])
groups = [[*group] for _, group in groups]
# 3rd element
grp_3rd = [[entry[2] for entry in group] for group in groups]
# you could sum it up right here
grp_3rd = [sum(float(entry[2]) for entry in group) for group in groups]
# or you could do to see each key and the corresponding sum i.e. {'1': 3222.0, '507': 1012.0}
grp_3rd = {group[0][0]: sum(float(entry[2]) for entry in group) for group in groups}
# continue on to your output
flatten = lambda list_: [sublist for l in list_ for sublist in l]
groups = [flatten(group) for group in groups]
output:
[['1', 'M', '6', '2', '1', 'W', '1400', '3', '1', 'M', '8', '8', '1', 'T', '101', '10', '1','W', '1700', '15', '1', 'M', '7', '16'],
['507', 'W', '1000', '1', '507', 'M', '4', '12', '507', 'M', '8', '20']]
The answer from Cedric below is easier to understand so if you can easily follow that here is how you could change it.
rows = [['507', 'W', '1000', '1'],
['1', 'M', '6', '2'],
['1', 'W', '1400', '3'],
['1', 'M', '8', '8'],
['1', 'T', '101', '10'],
['507', 'M', '4', '12'],
['1', 'W', '1700', '15'],
['1', 'M', '7', '16'],
['507', 'M', '8', '20']]
# get the output and sum directly
merged = {}
for row in rows:
if row[0] not in merged:
merged[row[0]] = [[], 0]
merged[row[0]][0].extend(row[1:])
merged[row[0]][1] += float(row[2])
# get the output and the list of 3rd elements
merged = {}
for row in rows:
if row[0] not in merged:
merged[row[0]] = ([], [])
merged[row[0]][0].extend(row[1:])
merged[row[0]][1].append(float(row[2]))
Something like this:
rows = [['507', 'W', '1000', '1'],
['1', 'M', '6', '2'],
['1', 'W', '1400', '3'],
['1', 'M', '8', '8'],
['1', 'T', '101', '10'],
['507', 'M', '4', '12'],
['1', 'W', '1700', '15'],
['1', 'M', '7', '16'],
['507', 'M', '8', '20']]
merged = {}
for row in rows:
if row[0] in merged:
merged[row[0]].extend(row[1:])
else:
merged[row[0]] = row
print(merged)
Output:
{
'507': ['507', 'W', '1000', '1', 'M', '4', '12', 'M', '8', '20'],
'1': ['1', 'M', '6', '2', 'W', '1400', '3', 'M', '8', '8', 'T', '101', '10', 'W', '1700', '15', 'M', '7', '16']
}
Or .extend(row) if you really want to repeat the ID

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)))}

Categories

Resources