Fuss
Fuss

Reputation: 11

Equal elements in list of lists. Delete one

I have a list of lists

list = [[-2.0, 5.0], [-1.0, -3.0], [1.0, 3.0], [2.0, -5.0]]

What I want to do is delete one the elements of same value should I divide first element with second. For example [-2.0, 5.0] = -2/5 and [2.0, -5.0] = -2/5. I want to delete either [-2.0, 5.0] or [2.0, -5.0] since they produce the same value.

Any ideas?

Upvotes: 1

Views: 141

Answers (5)

Greg Nisbet
Greg Nisbet

Reputation: 6994

Quick and dirty way, since keys in a dictionary are unique.

{num/denom : [num, denom] for (num, denom) in lst}.values()

In general, comparing floats using == is unreliable, it's normally better to check if they're within a tolerance. e.g.

abs(x-y) < tolerance

a more robust way would might look like the following. An else attached to a for loop just means do this unless you exited the loop early. It's quite handy. This version, however, is quadratic rather than linear time.

div = lambda x,y : x/y

unique = []
for j in range(len(lst)):
    for i in range(j):
        if abs( div(*lst[i])-div(*lst[j]) ) < tolerance:
            break
    else
        unique.append(lst[j])

unique

Upvotes: 0

James Sapam
James Sapam

Reputation: 16940

Can i try like this:

Tuple could be a dictionary key, so I converted the list into tuple after changing to abs value of the list element and keeping the original list as the values.

>>> lis
[[-2.0, 5.0], [-1.0, -3.0], [1.0, 3.0], [2.0, -5.0]]
>>> dict([(tuple([abs(x[0]), abs(x[1])]), x) for x in lis]).values()
[[2.0, -5.0], [1.0, 3.0]]
>>>

Upvotes: 1

ssm
ssm

Reputation: 5373

I would first get a unique set of ratios using set:

In [1]: lst = [[-2.0, 5.0], [-1.0, -3.0], [1.0, 3.0], [2.0, -5.0]]

In [2]: rs = list(set([ l[0]/l[1]  for l in lst]))

And then just filter out the first occurance of the ratios:

In [3]: [ filter(lambda m: m[0]/m[1] == r  , lst  )[0]    for r in rs ]
Out[3]: [[-2.0, 5.0], [-1.0, -3.0]]

In [4]:

Upvotes: 0

IceArdor
IceArdor

Reputation: 2041

If you want to eliminate all equivalent fractions (meaning [-2.0, 5.0] and [4.0, -10.0] are considered equivalent), then the following code would work.

seen = set()
for numerator, denominator in lst:
    quotient = numerator / denominator
    if quotient not in seen:
        seen.add(quotient)
        yield numerator, denominator

Otherwise, if you want the final list to contain both [-2.0, 5.0] and [4.0, -10.0]:

seen = set()
for numerator, denominator in lst:
    value = (abs(numerator), abs(denominator), sign(numerator)*sign(denominator))
    if value not in seen:
        seen.add(value)
        yield numerator, denominator

If you're writing this in Python, a language that lacks a sign function, you'll either need to use math.copysign or (numerator > 0) ^ (denominator > 0) where ^ is the xor operator.

This code assumes both numerator and denominator are nonzero.

If you really are keeping a list of numerator-denominator number pairs, consider storing the pairs as immutable tuples or better yet, as Python fractions.

Upvotes: 0

JB333
JB333

Reputation: 244

Assuming all your values are all floats (so you can always use float division) you can do the following:

my_list = [[-2.0, 5.0], [-1.0, -3.0], [1.0, 3.0], [2.0, -5.0]]
values_seen = []
new_list = []

for x,y in my_list:
    if x/y in values_seen:
        continue
    else:
        values_seen.append(x/y)
        new_list.append([x,y])

Now the list you want will be stored as new_list. Note that you should avoid writing a value to the keyword list as you have above.

*Clarification, I am assuming that if you have any more than 2 values that return the same ratio (for example [[1,3],[2,6],[3,9]]) you will want to keep only one of these.

Upvotes: 0

Related Questions