1

If I have a multidimensional list called t and I append some numbers from the list into a new list called TC, how do I take all of the numbers that were not appended into the new list and put them in their own list, called nonTC? For example:

t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]

And I write some conditions to append only some values from each list to create the new list, TC:

TC = [[3, 4, 6], [9, 7, 2], [5]]

How do I append the values not included in TC into its own list? So I would get:

nonTC = [[1, 5, 7],[4, 5],[3,4]]
MAJ
  • 437
  • 5
  • 17
  • 1
    It would be good to see what you've tried. How do you expect to handle repeats, does order matter? Using `set`s would make this relative easy, e.g. `[sorted(set(a).difference(b)) for a, b in zip(t, TC)]` – AChampion Feb 09 '19 at 21:29

2 Answers2

3

You can use list comprehensions and a list of sets to filter your original list:

t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]

# filter sets - each index corresponds to one inner list of t - the numbers in the 
# set should be put into TC - those that are not go into nonTC
getem = [{3,4,6},{9,7,2},{5}]

TC = [ [p for p in part if p in getem[i]] for i,part in enumerate(t)]
print(TC)

nonTC = [ [p for p in part if p not in getem[i]] for i,part in enumerate(t)]     
print(nonTC)

Output:

[[3, 4, 6], [9, 7, 2], [5]] # TC
[[1, 5, 7], [4, 5], [3, 4]] # nonTC

Readup:

And: Explanation of how nested list comprehension works?


Suggestion for other way to do it, creds to AChampion:

TC_1 = [[p for p in part if p in g] for g, part in zip(getem, t)]
nonTC_1 = [[p for p in part if p not in g] for g, part in zip(getem, t)]

See zip() - it essentially bundles the two lists into an iterable of tuples

( (t[0],getem[0]), (t[1],getem[1]) (t[2],getem[2])) 

Add-On for multiple occurences - forfeiting list comp and sets:

t = [[1, 3, 4, 5, 6, 7, 3, 3, 3],[9, 7, 4, 5, 2], [3, 4, 5]]

# filter lists - each index corresponds to one inner list of t - the numbers in the list
# should be put into TC - those that are not go into nonTC - exactly with the amounts given
getem = [[3,3,4,6],[9,7,2],[5]]

from collections import Counter
TC = []
nonTC = []
for f, part in zip(getem,t):
    TC.append([])
    nonTC.append([])
    c = Counter(f) 
    for num in part:
        if c.get(num,0) > 0:
            TC[-1].append(num)
            c[num]-=1
        else:
            nonTC[-1].append(num)            

print(TC)    # [[3, 4, 6, 3], [9, 7, 2], [5]]
print(nonTC) # [[1, 5, 7, 3, 3], [4, 5], [3, 4]]

It needs only 1 pass over your items instead of 2 (seperate list comps) which makes it probably more efficient in the long run...

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • 2
    You could alternatively use `zip()` instead of indexing in `getem`, e.g. `[[p for p in part if p not in g] for g, part in zip(getem, t)]` – AChampion Feb 09 '19 at 21:33
  • @AChampion edited and credited in case your comment vanishes somehow – Patrick Artner Feb 09 '19 at 21:38
  • What if there are repeats in the list? For example, if 't=[[1, 3, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]' and only one of the 3's in the first set was appended into TC? – MAJ Feb 09 '19 at 21:50
  • @May use an old fashioned loop and remove a number when taken from the corresponding set so it wont get into again. For the nonTC you would do it similarly -you would need to keep the original sets and use copies. Thats quite out of your original question though ... – Patrick Artner Feb 09 '19 at 21:52
0

Just out of curiosity, using NumPy:

import numpy as np

t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]
TC = [[3, 4, 6], [9, 7, 2], [5]]

print([np.setdiff1d(a, b) for a, b in zip(t, TC)])
#=> [array([1, 5, 7]), array([4, 5]), array([3, 4])]
iGian
  • 11,023
  • 3
  • 21
  • 36