Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 31, 2013 21:40:08

bystander
Зарегистрирован: 2013-08-12
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Здравствуйте, только начал осваивать Питон, написал скрипт, изменяющий табличку, но он работает не совсем корректно.
Дано: список d вида

[[ФИО1, [год, дата]], 
[ФИО2, [год, дата]], 
[ФИО1, [год, дата]], 
[ФИО3, [год, дата]]]

Нужно найти элементы списка с уникальными ФИО и добавить к ним все даты из элементов с такими же ФИО, а потом удалить те элементы, из которых бралась дата, чтобы получилось что-то вроде:
[[ФИО1, [год, дата, дата]], 
[ФИО2, [год, дата]], 
[ФИО3, [год, дата]]]

Код:
def diff():
    i = 0
    q = 0
    while i < len(d):    #крутим цикл для каждого ФИО
        while q < len(d):    #крутим цикл для каждой даты
            if d[i][0] == d[i+q][0] and d[i][1][1] != d[i+q][1][1]:    #если одинаковые имена, но разные даты
                d[i][1].append(d[i+q][1][1])    # добавляем дату в подсписок элемента
                del(d[i+q])    #удаляем строку, из которой была взята дата
            q = q+1
        i = i+1
    return d[j]    #возвращаем в список обновлённую стоку
 
j = 0
while j < len(d):
    d[j] = diff()
    j = j+1
 
print(d)
Добавление дат и удаление дубликатов работают для первой строки, ко второй добавляется всего пара значений, с остальными вообще ничего не происходит. Возможно изменяется длинна списка и потому не работает len(d)? Подскажите, что не так с этим кодом, и как сделать лучше (подозреваю, три цикла while - это не самый лучший выбор). В подсознании крутится range()…

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

Отредактировано bystander (Авг. 31, 2013 22:00:01)

Офлайн

#2 Авг. 31, 2013 21:54:43

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Правильно крутится. Самый простой способ - использование xrange (аналог range, но возвращает итератор) и цикла for.

data = [2, 3, 4, 5, 6]
for pos in xrange(len(data)):
    print "data in pos %s = %s" % (pos, data[pos])

В этом случае len() определяется один раз для создания итератора, но если вы меняете список внутри цикла, то в этом случае лучше использовать явный проход по списку, так как len() для базового списка будет неверен через одно удаление, т.е. длина списка станет меньше начальной и когда дело дойдет до позиции последнего элемента (точнее элемента позиция которого больше фактического размера нового списка), то она не будет совпадать с фактической и программа вернет ошибку IndexError, т.е. ошибка индекса (например, вы пытаетесь вызвать 10 элемент в списке из 9).

Для этого случая по списку лучше проходить явно, т.е.

data = [2, 3, 4, 5, 6]
for line in data:
    print line

Такой подход позволяет выбирать элементы из уже существующего списка на каждом шаге. Если элементы будут удалятся в цикле, то просто будет меньше итераций (или шагов).



Отредактировано 4kpt (Авг. 31, 2013 22:08:57)

Офлайн

#3 Авг. 31, 2013 22:24:25

bystander
Зарегистрирован: 2013-08-12
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Спасибо, с

for line in data:
    line = diff()
заработало быстрее, но всё равно даты нормально собираются только для первой строки. Не подскажете, из-за чего это?

Офлайн

#4 Авг. 31, 2013 23:52:02

dimy44
От: Евпатория
Зарегистрирован: 2012-04-21
Сообщения: 463
Репутация: +  42  -
Профиль  

поиск и сравнение в списке

Выведите на экран с помощью print значения переменных в нужных вам местах и вы увидете что с ними происходит с каждым шагом. Так и быстрей вникнете что к чему.

Офлайн

#5 Авг. 31, 2013 23:58:42

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Или дайте свой код. А то как-то гадать сложновато :) Нужно посмотреть.



Офлайн

#6 Сен. 1, 2013 01:14:59

bystander
Зарегистрирован: 2013-08-12
Сообщения: 11
Репутация: +  0  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

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

x = open("D:\\python\\test table.txt", "r")
f = x.read().split('\n')
d = []
for line in f:#тут табличка приводится в вид, описанный выше
    element = line.split('\t') 
    x = element[0]
    y = element[1].split(':') 
    t = [x, y]
    d.append(t)
def diff():
    i = 0 
   #в этом месте print(line) выводит строки по порядку
    q = 0
    while i < len(d):
        while q < len(d):
            #в этом месте print(line) выводит каждую строкустолько раз, сколько задано в обеих циклах
            if d[i][0] == d[i+q][0] and d[i][1][1] != d[i+q][1][1]: 
                line[1].append(d[i+q][1][1])
                del(d[i+q])
                #в этом месте print(line) несколько раз выводит первую строку, каждый раз добавляя к ней новую найденную дату и пару раз раз вторую строку добавляя к ней новую найденную дату
            q = q+1
        i = i+1        
    return line
for line in d:
    line = diff()
print(d)

print(d) выводит список, в котором для первого элемента выполнены условия, описанные в стартовом посте, для воторго элемента собрано несколько дат и дальше в списке встречаются элементы с таким же ФИО, остальные элементы не тронуты.
Ещё одна небольшая проблема: строка почему-то не хочет разделяться по пробелу, при этом split(':') работает.

Отредактировано bystander (Сен. 1, 2013 01:56:46)

Офлайн

#7 Сен. 1, 2013 09:11:47

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Использование while крайне нежелательно. Я же Вам написал. Напилил код с циклом for. Постарался сделать попроще. Еще проще сложновато. Попытайтесь вникнуть в идею. Первая строка # coding: utf-8 нужна для питона версии 2.Х. Если Вы работаете с 3.Х, то можно ее удалить.

# coding: utf-8
data = [[u"Иванов", [1999, u"Дата 1 - Иванов"]],
        [u"Петров", [1999, u"Дата 1 - Петров"]],
        [u"Клачин", [1999, u"Дата 1 - Клачин"]],
        [u"Клачин", [1999, u"Дата 2 - Клачин"]],
        [u"Петров", [1999, u"Дата 2 - Петров"]],
        [u"Петров", [1999, u"Дата 3 - Петров"]],
        [u"Иванов", [1999, u"Дата 2 - Иванов"]],
        [u"Клачин", [1999, u"Дата 3 - Клачин"]],
        [u"Иванов", [1999, u"Дата 3 - Иванов"]],
        [u"Петров", [1999, u"Дата 4 - Петров"]],
        [u"Иванов", [1999, u"Дата 4 - Иванов"]],
        [u"Петров", [1999, u"Дата 5 - Петров"]],
        [u"Шудрин", [1999, u"Дата 1 - Шудрин"]],
        [u"Клачин", [1999, u"Дата 4 - Клачин"]]]
for fline in data:
    for nline in data[data.index(fline) + 1:]:
        if fline[0] == nline[0]:
            fline[1].append(nline[1][1])
            # Если могут быть полностью одинаковые данные по одному человеку
            #data.pop(data.index(nline))
            # Если полностью идентичных данных быть не может
            data.remove(nline)           
for line in data:
    print repr(line).decode("unicode_escape") # Для 2.Х
    #print(line) # Для 3.Х

По разбору файла не знаю. Нужно увидеть сам файл. Выложите…



Отредактировано 4kpt (Сен. 1, 2013 09:41:03)

Офлайн

#8 Сен. 1, 2013 10:33:52

sp3
От:
Зарегистрирован: 2010-01-12
Сообщения: 405
Репутация: +  18  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

Ежели порядок данных неважен и их много предлагаю померятся п…ми

data = [[u"Иванов", [1999, u"Дата 1 - Иванов"]],
        [u"Клачин", [1999, u"Дата 4 - Клачин"]]]
for x in range(200000):
    name = "ivanov_%s"%(x%30)
    date =  "ivanov_%s"%(x%10)
    data.append([name,[1999,date]]) 
 
from time import time
 
def timer(foo):
    def wrapped(*w):
        t = time()
        out = foo(*w)
        print foo.__name__, time() - t
        return out
    return wrapped
 
 
@timer
def lists(data):
    for fline in data:
        for nline in data[data.index(fline) + 1:]:
            if fline[0] == nline[0]:
                fline[1].append(nline[1][1])
                # Если могут быть полностью одинаковые данные по одному человеку
                #data.pop(data.index(nline))
                # Если полностью идентичных данных быть не может
                data.remove(nline)
    return data
 
 
@timer             
def dicts(data):
    out = {}
    for name,(year,date) in data:
        all_date = out.get(name,[year])
        # только уникальные значения
        if date not in all_date:
            out[name] = all_date
    return out
 
 
newdata = dicts(data)
newdata = lists(data)



Офлайн

#9 Сен. 1, 2013 11:17:48

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

sp3
Что-то Вы натворили не то :) Посмотрите Ваш и мой результаты. Нужно, чтобы по идентичным фамилиям добавлялись даты во внутренний список, т.е. количество дат должно увеличиваться. Хотя подход интересен…

bystander
Дано: список d вида [[ФИО1, ],
[ФИО2, ],
[ФИО1, ],
[ФИО3, ]]
Нужно найти элементы списка с уникальными ФИО и добавить к ним все даты из элементов с такими же ФИО, а потом удалить те элементы, из которых бралась дата, чтобы получилось что-то вроде:
[[ФИО1, ],
[ФИО2, ],
[ФИО3, ]]



Офлайн

#10 Сен. 1, 2013 11:33:50

bismigalis
Зарегистрирован: 2010-10-02
Сообщения: 449
Репутация: +  47  -
Профиль   Отправить e-mail  

поиск и сравнение в списке

словарь рулит

from collections import defaultdict
d = defaultdict(lambda: ([],[]))
for name, (year, date) in lst:
    d[name][0].append(year)
    d[name][1].append(date)
out = [[name, [year[0]] + date] for name, (year, date) in d.items()]
print(out)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version