-2

I want to detect which item in a list that is replaced while ignoring occurance in the list, suppose I have:

before_list = ['C1', 'C16', 'C23', 'C14', 'C23', 'C13', 'C11', 'C19', 'C27', 'C10', 'C16', 'C28', 'C11', 'C8', 'C2', 'C27', 'C18', 'C27']

after_list = ['C1', 'C16', 'C23', 'C23', 'C13', 'C11', 'C19', 'C10', 'C16', 'C28', 'C8', 'C18', 'C27', 'C1', 'C14', 'C22', 'C16', 'C6']

I want to detect which item has been replaced by comparing before_list and after_list, and produce a list of the replaced item

to_be_replaced = ['C27','C11','C2','C27']
replace_with = ['C1','C22','C16','C6']

Can anyone help me with how to do this?

Doggy Face
  • 357
  • 1
  • 4
  • 12
  • 4
    Can you demonstrate *any* effort at solving this yourself? – Scott Hunter Nov 13 '20 at 12:26
  • @JohnColeman: As wonderful as `zip` is, it isn't the solution to this problem. – Scott Hunter Nov 13 '20 at 12:28
  • 1
    Where is `C14->Nothing` replacement (4th element in source list was removed) in your "result"? – Patrick Artner Nov 13 '20 at 12:29
  • @ScottHunter I misread it. I was thinking of parallel replacements of equal size lists. In effect, these are more like multi-sets than lists. – John Coleman Nov 13 '20 at 12:30
  • `set(before_list) - set(after_list)` will give you the elements only in the first list, subtracting the `after_list_set` from the `before_list_set` will give you what's in the second list and not in the first. – MatsLindh Nov 13 '20 at 12:32
  • @MatsLindh: How will that handle duplicates? – Scott Hunter Nov 13 '20 at 12:35
  • @PatrickArtner: `C14` is in both source lists. – Scott Hunter Nov 13 '20 at 12:36
  • @ScottHunter it won't. I didn't read any decent specification about that in the question as it leaves a lot of details to be assumed. Which is why I added it as a comment, and not as an answer. – MatsLindh Nov 13 '20 at 12:36
  • 1
    Since you don't care about order of occurrences, there will be multiple solutions. What criteria, if any, do you use to pick between multiple solutions? The problem seems unclear as stated. You could use `Counter` on both lists to abtain the sublists where the counts differ. – John Coleman Nov 13 '20 at 12:36
  • Does this answer your question? [Get difference between two lists](https://stackoverflow.com/questions/3462143/get-difference-between-two-lists) – Rhayene Nov 13 '20 at 14:28

2 Answers2

1

This produces the desired lists (if not in the order specified):

i,j = 0,0
bl = sorted(before_list)
al = sorted(after_list)
tbr =[]
rw = []
while i<len(before_list) and j<len(after_list):
    if bl[i]<al[j]:
        tbr.append(bl[i])
        i += 1
    elif bl[i]>al[j]:
        rw.append(al[j])
        j += 1
    else:
        i += 1
        j += 1
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
1

If I understand your problem correctly, the following gives one solution:

from collections import Counter
before_list = ['C1', 'C16', 'C23', 'C14', 'C23', 'C13', 'C11', 'C19', 'C27', 'C10', 'C16', 'C28', 'C11', 'C8', 'C2', 'C27', 'C18', 'C27']

after_list = ['C1', 'C16', 'C23', 'C23', 'C13', 'C11', 'C19', 'C10', 'C16', 'C28', 'C8', 'C18', 'C27', 'C1', 'C14', 'C22', 'C16', 'C6']

counts1 = Counter(before_list)
counts2 = Counter(after_list)
to_be_replaced = []
replace_with = []
for x,c1 in counts1.items():
  c2 = counts2[x]
  if c2 < c1:
    to_be_replaced.extend([x]*(c1 - c2))
for y,c2 in counts2.items():
  c1 = counts1[y]
  if c1 < c2:
    replace_with.extend([y] * (c2 - c1))

Which yields

to_be_replaced = ['C11', 'C27', 'C27', 'C2']
replace_with = ['C1', 'C16', 'C22', 'C6']
John Coleman
  • 51,337
  • 7
  • 54
  • 119