-9

For example, I have one list as below:

l1 = [1, 2, 3, 4]

I have another list lx to compare with l1 and need to decide whether lx matches l1. A successful match is defined as below:

For each element e in lx, e must be in l1 too; and for any two sequential elements e1 and e2, if e1 appears before e2, then e1 must also appear before e2 in l1.

Some examples are below and their match status with l1 is provided:

l2 = [2, 1]      # fails
l3 = [1, 2, 4]   # succeeds
l4 = [2, 3]      # succeeds
l5 = [2, 3, 1]   # fails
l6 = [1,2,3,4,5] # fails

UPDATE for more complicated cases:

l1 = [1, 2, 3, 4]
l2 = [{2}, {1}]
l2 = [{2,1}, {1,3}]

l1 doesn't change, but in the other list, it's always a set of lists. For this example:

l2 = [{2,1}, {1,3}]

It can be expanded into:

l2 = [[2,1], [2,3], [1,1], [1,3]] 

which means as long as one of the 4 lists in l2 matches l1, it is a successful match. Since [1,3] matches l1=[1,2,3,4], the whole l2 can match.

So one solution may be first flatten the l2 into the new l2, and then the all(e in i for e in b) can be used.

marlon
  • 6,029
  • 8
  • 42
  • 76
  • 2
    Are the values unique? – mozway Dec 23 '21 at 06:32
  • 2
    https://idownvotedbecau.se/noattempt/, would gladly upvote if you show your previous efforts, because the question itself is well organzied... – Adam.Er8 Dec 23 '21 at 06:34
  • 4
    You have multiple gold badges and a 7-year-old account, so you should well understand by now that [some research is expected before asking](https://meta.stackoverflow.com/questions/261592), if only so that you can narrow down the question you ask to the *actual question that you have*. What part of this task do you find difficult? What happened when you tried to write the code? – Karl Knechtel Dec 23 '21 at 06:39
  • @mozway, not necessarily unique. – marlon Dec 23 '21 at 06:40

3 Answers3

3

A simple (non optimal) solution is to rework l1 to keep only elements of the second list, and check equality:

def check(a, b):
    S = set(b)
    return b == [x for x in a if x in S]

check(l1, l3)

Test:

for l in [l2, l3, l4, l5, l6]:
    print(check(l1, l))

Output:

False
True
True
False
False
mozway
  • 194,879
  • 13
  • 39
  • 75
2

Try this:

def is_subsequence(list1, list2):
    return set(list2) <= set(list1) and list2 == sorted(list2, key=list1.index)

Not the most optimal method, but it basically sorts the smaller list using the indices of the main list and checks if the elements are still in the same positions:

print(is_subsequence(l1, [2, 1]))           # False
print(is_subsequence(l1, [1, 2, 4]))        # True
print(is_subsequence(l1, [2, 3]))           # True
print(is_subsequence(l1, [2, 3, 1]))        # False
print(is_subsequence(l1, [1, 2, 3, 4, 5]))  # False
Selcuk
  • 57,004
  • 12
  • 102
  • 110
1

Here is an efficient solution. For each element in the second list, get the next element of the first one until you have a match. If you reach the end of the first list before you matched all, this is False else True

def check(a, b):
    i = iter(a)
    return all(e in i for e in b)

Or manual version:

def check(a, b):
    i = iter(a)
    for e in b:
        try: 
            while e != next(i):
                pass
        except StopIteration:
            return False
    return True

Test:

for l in [l2, l3, l4, l5, l6]:
    print(check(l1, l))

Output:

False
True
True
False
False
mozway
  • 194,879
  • 13
  • 39
  • 75
  • 1
    Looks like a complicated version of the old `return all(e in i for e in b)` :-P – Kelly Bundy Dec 23 '21 at 07:00
  • @Kelly haven't slept for a while, allow me to be less pythonic that usual ;) – mozway Dec 23 '21 at 07:09
  • @mozway, can you please add back the first version of this more efficient algorithm? My actual case is more complicated and this current short version is less helpful than the original long version. I didn't save the longer version when you first post it. – marlon Dec 23 '21 at 08:46
  • @marlon check the [old revisions](https://stackoverflow.com/posts/70458685/revisions) of the answer, changes are tracked ;) – mozway Dec 23 '21 at 08:57
  • Out of curiosity, how different is your actual use case? – mozway Dec 23 '21 at 08:58
  • Let me update the original question. – marlon Dec 23 '21 at 09:02
  • @mozway please see my UPDATES. – marlon Dec 23 '21 at 09:11
  • @marlon I saw, however this is now a different problem. Also, sets are unordered, so you can't reliably generate your list of lists from the list of sets. – mozway Dec 23 '21 at 11:07
  • @mozway The way they want to use them, that unsortedness doesn't matter. – Kelly Bundy Dec 23 '21 at 11:26
  • @mozway, 'generate your list of lists from the list of sets' won't be an issue. For example [{1}, {2,3}] == [[1,2], [1,3]] == [[1,3], [1,2]]. Would this make it easier? – marlon Dec 23 '21 at 16:10
  • The "manual" version would btw only need a tiny change, and the short version could use something neat (could be *very* neat if the `set` class wasn't missing a method...). – Kelly Bundy Dec 23 '21 at 16:53
  • @KellyBundy I can't figure out how to make a new 'b' for the outer loop without first expanding the list of sets into list of lists. – marlon Dec 23 '21 at 17:58
  • If you unchange this question (I think it was bad to change it in the first place) and post it as a proper new question, I could answer it there. – Kelly Bundy Dec 23 '21 at 18:03
  • Yes. I will write a new one. – marlon Dec 23 '21 at 18:06
  • @KellyBundy, please see: https://stackoverflow.com/questions/70465931/how-to-do-sub-sequence-match-for-a-simple-list-and-a-list-of-sets – marlon Dec 23 '21 at 18:12