Groupby elements in a list of lists using strings from another list

Viewed 47

I have the following list of lists

listA = [
    ["4YBB|1|AA|A|262", "4YBB|1|AA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|A|263", "tSH", 'empty', 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|C|264", "ntSH", 'empty', "5BPh", 'empty'], 
    ["4YBB|1|AA|G|259", "4YBB|1|AA|C|267", "cWW", 'empty', 'empty', 'empty'], 
    ["4WOI|1|DA|A|262", "4WOI|1|DA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4WOI|1|DA|C|264", "4WOI|1|DA|G|265", 'empty', "s35", 'empty', 'empty']
    ]

I would like to group these based on identifiers from another list and they must be ordered the same way as the elements in the identifiers list:

identifiers = ["4YBB|1|AA", "4WOI|1|DA"]

As you can see, the identifiers are subset of the string element 1 and 2 of the inner list. The identifiers will always be the same for element 1 and 2 of the inner list. The desired output is as follows:

desiredoutput = [
              [
                ["4YBB|1|AA|A|262", "4YBB|1|AA|A|263", 'empty', "s35", 'empty', 'empty'], 
                ["4YBB|1|AA|U|261", "4YBB|1|AA|A|263", "tSH", 'empty', 'empty', 'empty'], 
                ["4YBB|1|AA|U|261", "4YBB|1|AA|C|264", "ntSH", 'empty', "5BPh", 'empty'], 
                ["4YBB|1|AA|G|259", "4YBB|1|AA|C|267", "cWW", 'empty', 'empty', 'empty'],
              ],
              [ 
                ["4WOI|1|DA|A|262", "4WOI|1|DA|A|263", 'empty', "s35", 'empty', 'empty'], 
                ["4WOI|1|DA|C|264", "4WOI|1|DA|G|265", 'empty', "s35", 'empty', 'empty']
              ]
            ]

How can I achieve this using the itertools groupby method or any other methods?

3 Answers

This is one approach using collections module.

Ex:

from collections import defaultdict, OrderedDict

listA = [
    ["4YBB|1|AA|A|262", "4YBB|1|AA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|A|263", "tSH", 'empty', 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|C|264", "ntSH", 'empty', "5BPh", 'empty'], 
    ["4YBB|1|AA|G|259", "4YBB|1|AA|C|267", "cWW", 'empty', 'empty', 'empty'], 
    ["4WOI|1|DA|A|262", "4WOI|1|DA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4WOI|1|DA|C|264", "4WOI|1|DA|G|265", 'empty', "s35", 'empty', 'empty']
    ]
identifiers = ["4YBB|1|AA", "4WOI|1|DA"]
result = defaultdict(list)

for i in listA:
    key = i[0].rsplit('|', 2)[0]               #Get Key
    if key in identifiers:                     #Check in identifiers 
        result[key].append(i)                  #Group

result = OrderedDict(sorted(result.items(), key=lambda x: identifiers.index(x[0]))) #Sort base on identifiers 
print(result.values())

Output:

[[['4YBB|1|AA|A|262', '4YBB|1|AA|A|263', 'empty', 's35', 'empty', 'empty'],
  ['4YBB|1|AA|U|261', '4YBB|1|AA|A|263', 'tSH', 'empty', 'empty', 'empty'],
  ['4YBB|1|AA|U|261', '4YBB|1|AA|C|264', 'ntSH', 'empty', '5BPh', 'empty'],
  ['4YBB|1|AA|G|259', '4YBB|1|AA|C|267', 'cWW', 'empty', 'empty', 'empty']],
 [['4WOI|1|DA|A|262', '4WOI|1|DA|A|263', 'empty', 's35', 'empty', 'empty'],
  ['4WOI|1|DA|C|264', '4WOI|1|DA|G|265', 'empty', 's35', 'empty', 'empty']]]

Just an FYI. Using itertools.groupby

from itertools import groupby

listA = [
    ["4YBB|1|AA|A|262", "4YBB|1|AA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|A|263", "tSH", 'empty', 'empty', 'empty'], 
    ["4YBB|1|AA|U|261", "4YBB|1|AA|C|264", "ntSH", 'empty', "5BPh", 'empty'], 
    ["4YBB|1|AA|G|259", "4YBB|1|AA|C|267", "cWW", 'empty', 'empty', 'empty'], 
    ["4WOI|1|DA|A|262", "4WOI|1|DA|A|263", 'empty', "s35", 'empty', 'empty'], 
    ["4WOI|1|DA|C|264", "4WOI|1|DA|G|265", 'empty', "s35", 'empty', 'empty']
    ]
identifiers = ["4YBB|1|AA", "4WOI|1|DA"]

result = [list(value) for k, value in groupby(sorted(listA, key=lambda x: x[0].rsplit('|', 2)[0]), lambda x: x[0].rsplit('|', 2)[0]) if k in identifiers]
print(result)

Here is a way to do it :

output = []
inter = []
prev_id = listA[0][0]
for element in listA:
    if element[0]==prev_id:
        inter.append(element)
    else:
        output.append(inter)
        prev_id = element[0]
        inter=[element]

Output :

[[['4YBB|1|AA|A|262', '4YBB|1|AA|A|263', 'empty', 's35', 'empty', 'empty']],
 [['4YBB|1|AA|U|261', '4YBB|1|AA|A|263', 'tSH', 'empty', 'empty', 'empty'],
  ['4YBB|1|AA|U|261', '4YBB|1|AA|C|264', 'ntSH', 'empty', '5BPh', 'empty']],
 [['4YBB|1|AA|G|259', '4YBB|1|AA|C|267', 'cWW', 'empty', 'empty', 'empty']],
 [['4WOI|1|DA|A|262', '4WOI|1|DA|A|263', 'empty', 's35', 'empty', 'empty']]]

As the identifiers will always be the same for element 1 and 2 of the inner list. - we can group on the needed slices with defaultdict:

from collections import defaultdict
import pprint

listA = [
    ["4YBB|1|AA|A|262", "4YBB|1|AA|A|263", 'empty', "s35", 'empty', 'empty'],
    ["4YBB|1|AA|U|261", "4YBB|1|AA|A|263", "tSH", 'empty', 'empty', 'empty'],
    ["4YBB|1|AA|U|261", "4YBB|1|AA|C|264", "ntSH", 'empty', "5BPh", 'empty'],
    ["4YBB|1|AA|G|259", "4YBB|1|AA|C|267", "cWW", 'empty', 'empty', 'empty'],
    ["4WOI|1|DA|A|262", "4WOI|1|DA|A|263", 'empty', "s35", 'empty', 'empty'],
    ["4WOI|1|DA|C|264", "4WOI|1|DA|G|265", 'empty', "s35", 'empty', 'empty']
    ]

groups = defaultdict(list)
for sub_l in listA:
    groups[sub_l[0][:10]].append(sub_l)

result = list(groups.values())
pprint.pprint(result)

The output:

[[['4YBB|1|AA|A|262', '4YBB|1|AA|A|263', 'empty', 's35', 'empty', 'empty'],
  ['4YBB|1|AA|U|261', '4YBB|1|AA|A|263', 'tSH', 'empty', 'empty', 'empty'],
  ['4YBB|1|AA|U|261', '4YBB|1|AA|C|264', 'ntSH', 'empty', '5BPh', 'empty'],
  ['4YBB|1|AA|G|259', '4YBB|1|AA|C|267', 'cWW', 'empty', 'empty', 'empty']],
 [['4WOI|1|DA|A|262', '4WOI|1|DA|A|263', 'empty', 's35', 'empty', 'empty'],
  ['4WOI|1|DA|C|264', '4WOI|1|DA|G|265', 'empty', 's35', 'empty', 'empty']]]
Related