Python, удаляющий пересечение из списка 2 из списка 1 [дубликат]

Предполагая, что они находятся в файле или массиве, просто замените его как пакет (то есть на всех сразу):

  $ input = str_replace (array ('.', ','  ), array ('', '.'), $ input);   

, а затем обрабатывать числа оттуда, полностью используя непринужденную типизацию PHP.

2
задан rook 23 August 2013 в 12:05
поделиться

4 ответа

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

code

with open("0.txt") as f:
    t=[x.rstrip("\n").split("\t") for x in f.readlines()]
    intervals=[(int(x[0]),int(x[1])) for x in t]

def find_ints(intervals, mn, mx):
    next_start = mn
    for x in intervals:
        if next_start < x[0]:
            yield next_start,x[0]
            next_start = x[1]
        elif next_start < x[1]:
            next_start = x[1]
    if next_start < mx:
        yield next_start, mx

print list(find_ints(intervals, 0, 200))

output :

(в примере, который вы указали)

[(0, 1), (8, 9), (12, 20), (30, 200)]
1
ответ дан Teudimundo 15 August 2018 в 16:17
поделиться
  • 1
    есть проблема: максимальный интервал в выходе заканчивается на: 9980032 Теперь диапазон вместо 200 теперь установлен на 249250622. Знаете ли вы, что происходит, или вам нужна дополнительная информация? Данные, которые я передал, форматируются в соответствии с запросом (порядок увеличения начальной позиции) – Irek 23 August 2013 в 14:43
  • 2
    Там не должно быть никаких проблем. Вы должны получить последний интервал как 9980032, 249250622. По крайней мере, это то, что он делает, если вы добавите интервал в том, который вы дали в качестве примера (например, (5, 9980032)), и вы используете 249250622 как mx – Teudimundo 23 August 2013 в 14:58
  • 3
    Я не знаю, я поставил файл здесь, если вы хотите проверить: dropbox.com/s/ftavov170n8987j/0 Используемый максимальный диапазон: 249250622 – Irek 23 August 2013 в 15:12
  • 4
    Я думаю, что я нашел проблему, когда вы читаете файл, который не преобразовывает строку в int, поэтому сравнение будет выполняться лексикографически, а не численно, я добавил код для чтения файла. – Teudimundo 25 August 2013 в 09:26

Если вы делаете заметку каждый раз, когда один из ваших интервалов ввода открывается или закрывается, вы можете делать то, что хотите, объединяя ключи opens и closes, сортировать в упорядоченный набор, «Хорошо, допустим, допустим, что каждая смежная пара чисел образует интервал, тогда я могу сосредоточить всю свою логику на этих интервалах как дискретные куски».

myRange = range(201)
intervals = [(1,5), (2,8), (9,12), (20,30)]
opens = {}
closes = {}

def open(index):
    if index not in opens:
        opens[index] = 0
    opens[index] += 1

def close(index):
    if index not in closes:
        closes[index] = 0
    closes[index] += 1

for start, end in intervals:
    if end > start: # Making sure to exclude empty intervals, which can be problematic later
        open(start)
        close(end)

# Sort all the interval-endpoints that we really need to look at
oset = {0:None, 200:None}
for k in opens.keys():
    oset[k] = None
for k in closes.keys():
    oset[k] = None
relevant_indices = sorted(oset.keys())

# Find the clear ranges
state = 0
results = []
for i in range(len(relevant_indices) - 1):
    start = relevant_indices[i]
    end = relevant_indices[i+1]

    start_state = state
    if start in opens:
        start_state += opens[start]
    if start in closes:
        start_state -= closes[start]

    end_state = start_state
    if end in opens:
        end_state += opens[end]
    if end in closes:
        end_state -= closes[end]
    state = end_state

    if start_state == 0:
        result_start = start
        result_end = end
        results.append((result_start, result_end))

for start, end in results:
    print(str(start) + " " + str(end))

Эти выходы :

0 1
8 9
12 20
30 200

Интервалы не нужно сортировать.

1
ответ дан alcedine 15 August 2018 в 16:17
поделиться
  • 1
    Хорошо работает, однако, когда 249250621 прошел как диапазон, ошибка памяти. Как я уже сказал, файлы огромные – Irek 23 August 2013 в 12:05
  • 2
    Я делю файл и диапазон на несколько частей, что должно сделать трюк. – Irek 23 August 2013 в 12:10
  • 3
    Ирек, я внес некоторые изменения, которые, как я думаю, помогут решить проблему нехватки памяти. Посмотрите, сделает ли это для вас. – alcedine 23 August 2013 в 12:32
  • 4
    Это здорово, работает очень быстро. На первый взгляд, похоже, работает так, как ожидалось. Спасибо, за готовое решение – Irek 23 August 2013 в 13:23
  • 5
    Я заметил первые несоответствия. Иногда он дает правильную начальную точку, но конечная точка похожа на значение в 2 раза выше – Irek 23 August 2013 в 14:09

Этот вопрос, кажется, является дубликатом Слияния интервалов в Python .

Если я хорошо понял проблему, у вас есть список интервалов (1 5; 2 8; 9 12; 20 30) и диапазон (0 200), и вы хотите получить позиции вне своих интервалов, но внутри заданного диапазона. Правильно?

Там есть библиотека Python, которая может помочь вам в этом: python-interval (также доступен из PyPI с помощью pip). Отказ от ответственности: Я сторонник этой библиотеки.

Предполагая, что вы импортируете эту библиотеку следующим образом:

import intervals as I

Довольно легко получить ответ. В принципе, вы сначала хотите создать дизъюнкцию интервалов на основе тех, которые вы предоставляете:

inters = I.closed(1, 5) | I.closed(2, 8) | I.closed(9, 12) | I.closed(20, 30)

Затем вы вычисляете дополнение этих интервалов, чтобы получить все, что «снаружи»:

compl = ~inters

Затем вы создаете союз с [0, 200], так как вы хотите ограничить точки до этого интервала:

print(compl & I.closed(0, 200))

В результате:

[0,1) | (8,9) | (12,20) | (30,200]
1
ответ дан Guybrush 15 August 2018 в 16:17
поделиться

Грубый алгоритм:

  1. создает массив логических значений, все установлены в false seen = [False]*200
  2. Итерации по входному файлу, для каждой строки start end установлено seen[start] .. seen[end] будет True
  3. После выполнения вы можете тривиально пройти массив, чтобы найти неиспользуемые интервалы.

С точки зрения оптимизаций , если список диапазонов входных данных сортируется по стартовому номеру, тогда вы можете отслеживать наивысшее число замеченных и использовать их для фильтрации диапазонов по мере их обработки - например что-то вроде

for (start,end) in input:
  if end<=lowest_unseen:
    next
  if start<lowest_unseen:
    start=lowest_unseen
  ...

, которое (игнорируя стоимость оригинального сорта) должно сделать всю вещь O (n) - вы проходите через массив один раз, чтобы пометить увиденное / невидимое и один раз вывести unseens.

Кажется, я чувствую себя хорошо. Вот код (неоптимизированный), предполагающий, что ваш входной файл называется input

seen = [False]*200
file = open('input','r')
rows = file.readlines()
for row in rows:
  (start,end) = row.split(' ')
  print "%s %s" % (start,end)
  for x in range( int(start)-1, int(end)-1 ):
    seen[x] = True

print seen[0:10]

in_unseen_block=False
start=1
for x in range(1,200):
  val=seen[x-1]
  if val and not in_unseen_block:
    continue
  if not val and in_unseen_block:
    continue
  # Must be at a change point.
  if val:
    # we have reached the end of the block
    print "%s %s" % (start,x)
    in_unseen_block = False
  else:
    # start of new block
    start = x
    in_unseen_block = True
# Handle end block
if in_unseen_block:
  print "%s %s" % (start, 200)

Я оставляю оптимизацию как упражнение для читателя.

1
ответ дан Oliver Matthews 15 August 2018 в 16:17
поделиться
  • 1
    извините, так как я все еще новичок в python, у меня есть некоторые проблемы при реализации ваших советов – Irek 23 August 2013 в 11:07
  • 2
    Хорошо, спасибо. Howebver с 249250621 как мой диапазон, ошибка памяти. Угадайте, что загрузка всех в память не была такой хорошей идеей – Irek 23 August 2013 в 12:03
Другие вопросы по тегам:

Похожие вопросы: