Получить индексы, соответствующие первым вхождениям в списке, сохраняя порядок [дубликат]

Я написал анализатор XML общего назначения, который может легко обрабатывать файлы GB. Он основан на XMLReader, и он очень прост в использовании:

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

Вот github repo: XmlExtractor

3
задан timgeb 2 January 2016 в 21:03
поделиться

2 ответа

Используйте enumerate, чтобы отслеживать индекс и набор, чтобы отслеживать увиденный элемент:

l = [1, 1, 2, 3]
inds = []
seen = set()
for i, ele in enumerate(l):
    if ele not in seen:
        inds.append(i)
    seen.add(ele)

Если вы хотите оба:

inds = []
seen = set()
for i, ele in enumerate(l):
    if ele not in seen:
        inds.append((i,ele))
    seen.add(ele)

Или, если вы хотите оба в разных списках:

l = [1, 1, 2, 3]
inds, unq = [],[]
seen = set()
for i, ele in enumerate(l):
    if ele not in seen:
        inds.append(i)
        unq.append(ele)
    seen.add(ele)

Использование набора является наилучшим подходом:

In [13]: l = [randint(1,10000) for _ in range(10000)]     

In [14]: %%timeit                                         
inds = []
seen = set()
for i, ele in enumerate(l):
    if ele not in seen:
        inds.append((i,ele))
    seen.add(ele)
   ....: 
100 loops, best of 3: 3.08 ms per loop

In [15]: timeit  OrderedDict((x, l.index(x)) for x in l)
1 loops, best of 3: 442 ms per loop

In [16]: l = [randint(1,10000) for _ in range(100000)]      
In [17]: timeit  OrderedDict((x, l.index(x)) for x in l)
1 loops, best of 3: 10.3 s per loop

In [18]: %%timeit                                       
inds = []
seen = set()
for i, ele in enumerate(l):
    if ele not in seen:
        inds.append((i,ele))
    seen.add(ele)
   ....: 
10 loops, best of 3: 22.6 ms per loop

Итак, для 100k элементов 10.3 секунд vs 22.6 ms ], если вы попробуете что-нибудь большее с меньшими обманами, например [randint(1,100000) for _ in range(100000)], у вас будет время прочитать книгу. Создание двух списков незначительно медленнее, но на порядок выше, чем при использовании list.index.

Если вы хотите получить значение за раз, вы можете использовать функцию генератора:

def yield_un(l):
    seen = set()
    for i, ele in enumerate(l):
        if ele not in seen:
            yield (i,ele)
        seen.add(ele)
3
ответ дан Padraic Cunningham 25 August 2018 в 03:10
поделиться

Я бы решил немного по-другому и использовал OrderedDict и тот факт, что метод list index вернет наименьший индекс элемента.

>>> from collections import OrderedDict
>>> lst = [1, 1, 2, 3]
>>> d = OrderedDict((x, lst.index(x)) for x in lst)
>>> d
OrderedDict([(1, 0), (2, 2), (3, 3)]

Если вам нужно список (с удалением дубликатов) и индексы отдельно, вы можете просто выдать:

>>> d.keys()
[1, 2, 3]
>>> d.values()
[0, 2, 3]
5
ответ дан timgeb 25 August 2018 в 03:10
поделиться
Другие вопросы по тегам:

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