How to check if 2 values inside a string in a list are not the same

Viewed 141

Super easy question. Let´s say I have this list in Python:

variables = ['A1,A1','A2,B2','A1,C2','B3,B3','C4,C4']

Now, I only need to keep those items where the value before and after the comma differs. In this case, the output would be:

result = ['A2,B2','A1,C2']

I already have a 'not-so-elegant' solution for this:

new_list = []
for i in range(len(variables)):
    j = variables[i].split(",")
    if j[0] != j[1].replace(" ", ""):
        z = "{},{}".format(j[0], j[1])
        new_list.append(z)

note: I had to add replace to remove whitespaces, but it´s not important...

Is there another (better) way to do this? Maybe regex?

note II: I also tried using a list comprehension:

lista_differents = ["{},{}".format(j[0], j[1]) for i in range(len(variables)) if j[0] != j[1].replace(" ", "")] 

But I still have to figure out how to add the line j = variables[i].split(",")

Any ideas?

7 Answers

You can try this with list comprehension and set. You basically split the string into 2 lists and then see if the set of those 2 elements has a len > 1 which means both are unique.

variables = ['A1,A1','A2,B2','A1,C2','B3,B3','C4,C4']

[i for i in variables if len(set(i.split(',')))>1]
['A2,B2', 'A1,C2']

If you are bothered about runtime then try this approach without a split(','). This is much much faster than the fastest one in benchmark.

[i for i in variables if len(set(i))>3]

EDIT: Adding benchmarking results (300000 length input array, macbook pro 13)

  • Akshay Sehgal (first) - 215 ms ± 9.77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • Akshay Sehgal (second) - 136 ms ± 195 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
  • Aviv Yaniv - 468 ms ± 39.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • jakub - 252 ms ± 29.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • Md. Ashraful Alam - 252 ms ± 29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Here is another approach which looks at the number of unique characters. Max allowed is 3 (i.e. letter, number, comma).

l = ['A1,A1','A2,B2','A1,C2','B3,B3','C4,C4'

[i for i in l if len(set(i)) > 3]

Output:

['A2,B2', 'A1,C2']

... and a friendly challenge to @ AkshaySehgal benchmarking. :-)

variables = ['A1,A1','A2,B2','A1,C2','B3,B3','C4,C4']

result = [a for a in variables if a.split(',')[0]!=a.split(',')[1].replace(" ", "")]

print(result)
[v for v in variables if str.__ne__(*v.replace(" ", "").split(","))]

You can use the str.__ne__(x1, x2) function, which is equivalent to x1 != x2. The * unpacks the list into separate arguments, so the outputs of .split(",") are made into two positional arguments (assuming there is only one , character in the string).

A solution without using additional memory:

variables = ['A1,A1','A2,B2','A1,C2','B3,B3','C4,C4']

def find_same_with_seperator(variables, SEPERATOR = ','):
    same_vars = []
    for v in variables:
        # Finding seperator index
        seperator_index = 0
        for i in range(len(v)):
            if SEPERATOR == v[i]:
                break
            seperator_index += 1
        # If no seperator
        if 0 == seperator_index:
            continue
        # Comparing parts
        before_seperator = 0
        after_seperator  = seperator_index + 1
        the_same = True
        while after_seperator < len(v):
            if v[before_seperator] != v[after_seperator]:
                the_same = False
                break
            before_seperator += 1
            after_seperator  += 1
        if the_same:
            same_vars.append(v)
    return same_vars

# ['A1,A1', 'B3,B3', 'C4,C4']
print(find_same_with_seperator(variables))

It's a time-honored tradition in Python to detect if items are different by putting them into a set and counting the number of elements.

[a for a in variables 
   if len(set(a.split(','))) > 1]

Another idiom in Python is to do "assignment" inside a list comprehension by iterating over a list with only one element. So another possible solution is:

[a for a in variables 
   for pair in [a.split(',')] 
   if pair[0] != pair[1]]

Python 3.8's walrus operator lets you write:

[a for a in variables 
   if (pair := a.split(','))[0] != pair[1]]

but I think that's rather ugly and hard to read.

This is just a classic problem. One suggested solution is checking on non-trivial rotation of the string. I believe this question has been used in several job interviews.

[x for x in variables if (x+','+x).find(x, 1, -1) == -1]

Out[183]: ['A2,B2', 'A1,C2']

P/s: This question is more about logic/algorithm than pandas or any specific programming language.

Related