2014-09-26 4 views
1

У меня есть список списковРавные элементы в списке списков. Удалить один

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

То, что я хочу сделать, это удалить один элементы же значения следует разделить первый элемент со вторым. Например, [-2.0, 5.0] = -2/5 и [2.0, -5.0] = -2/5. Я хочу удалить либо [-2.0, 5.0], либо [2.0, -5.0], так как они производят одинаковое значение.

Любые идеи?

+0

Почему это все 'поплавка ', если они округлены до ближайшего целого числа? –

+0

'list' - это ключевое слово. используйте что-то другое. – ssm

ответ

0

Предполагая, что все ваши ценности все поплавки (так что вы всегда можете использовать поплавок деление), вы можете сделать следующее:

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]) 

Теперь список вы хотите, будет сохранен как new_list. Обратите внимание, что вам следует избегать написания значения по ключевому слову list, как указано выше.

* Уточнение. Предполагаю, что если у вас есть более двух значений, возвращающих одинаковое соотношение (например, [[1,3],[2,6],[3,9]]), вы захотите сохранить только один из них.

0

Если вы хотите исключить все эквивалентные фракции (то есть [-2.0, 5.0] и [4.0, -10.0] считаются эквивалентными), тогда будет работать следующий код.

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

В противном случае, если вы хотите, чтобы окончательный список содержит как [-2,0, 5,0] и [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 

Если вы пишете это в Python, язык который не имеет функции sign, вам нужно будет либо использовать math.copysign, либо (numerator > 0)^(denominator > 0), где ^ является оператором xor.

Этот код предполагает, что числитель и знаменатель отличны от нуля.

Если вы действительно храните список номеров чисел с числителем-знаменателем, рассмотрите возможность хранения пар как неизменяемых кортежей или еще лучшего, как Python fractions.

0

Быстрый и грязный способ, поскольку ключи в словаре уникальны.

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

В целом, сравнение floats using == является ненадежным, обычно лучше проверить, находятся ли они в пределах допуска. например

abs(x-y) < tolerance 

более надежный способ может выглядеть следующим образом. Другой, привязанный к циклу for, означает это, если вы не вышли из цикла раньше. Это очень удобно. Однако эта версия является квадратичной, а не линейной.

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 
+0

'__hash__' и' __eq__' оба имеют проблемы с точностью по поплавкам, поэтому использование хэш-таблицы не помогло бы решить проблему. Например, если hash (-1/3.0)! = Hash (1/-3.0), у вас будет две записи в вашей хеш-таблице. – IceArdor

+0

Спасибо, мой ответ был не совсем понятен. Я не хотел утверждать, что версия словаря решит проблему толерантности, я имел в виду, что это просто и быстро и удалит дубликаты. Для встроенных типов, которые по крайней мере хэшируются, если две вещи сравниваются одинаково, то '__hash__' вернет одинаковое значение для обоих. –

+0

Возможно, стоит переупорядочить ваше решение как «быстрый и грязный dict», а затем «учитывая толерантность». Весь необходимый контент есть, просто сбив с первого взгляда. – IceArdor

1

Могу ли я попробовать, как это:

Кортеж может быть ключом словаря, поэтому я преобразовал список в кортеж после изменения в абс значение элемента списка и сохранить первоначальный список значений.

>>> 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]] 
>>> 
+1

Мне нравится это лучше, чем мое решение! +1 – ssm

0

Я бы сначала получить уникальный набор коэффициентов использования 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])) 

, а затем просто отфильтровать первое вхождение из соотношения:

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]: 
Смежные вопросы