объединение отсортированных списков кортежей в python - PullRequest
0 голосов
/ 15 февраля 2011

У меня есть n списков (n <10) кортежей в формате [(ListID, [(index, value), (index, value), ...)] и я хочу отсортировать их по индексу, чтобы перейти к следующим результат </p>

Example Input:
[('A',[(0.12, 'how'),(0.26,'are'),(0.7, 'you'),(0.9,'mike'),(1.9, "I'm fine too")]),
('B',[(1.23, 'fine'),(1.50, 'thanks'),(1.6,'and you')]),
('C',[(2.12,'good'),(2.24,'morning'),(3.13,'guys')])]

Desired Output:
[('A', ( 0.12, 'how')),
('A', ( 0.26, 'are')),
('A', ( 0.7, 'you')),
('A', ( 0.9, 'mike')),
('B',(1.23, 'fine')),
('B',(1.50, 'thanks')),
('B',(1.6,'and you')),
('A', (1.9, "I'm fine too")),
('C',(2.12,'good')),
('C',(2.24,'morning')),
('C',(3.13,'guys'))]   

Я знаю, что код некрасив, особенно это касается элемента индексов [0] [- 1] [1], но кто-нибудь может сказать мне, что я делаю неправильно?

content = []    
max = 0.0
first = True 
Done = False
finished = []
while not Done:
    for item in flow:
        if len(finished) == 4:
            Done = True
            break
        if len(item[1]) == 0:
            if item[0] not in finished:
                finished.append(item[0])
            continue
        if first == True:
            max = item[1][-1][0]
            content.append((item[0], item[1].pop()))
            first = False 
            continue
        if item[1][-1][0] > max:
            max = item[1][-1][0]
            content.append((item[0], item[1].pop()))
            content = sorted(content, key=itemgetter(1))    

    first = True    

UPDATE: спасибо всем

Ответы [ 4 ]

5 голосов
/ 15 февраля 2011
>>> from operator import itemgetter
>>> import pprint
>>> pprint.pprint(sorted(((i,k) for i,j in INPUT for k in j), key=itemgetter(1)))
[('A', (0.12, 'how')),
 ('A', (0.26000000000000001, 'are')),
 ('A', (0.69999999999999996, 'you')),
 ('A', (0.90000000000000002, 'mike')),
 ('B', (1.23, 'fine')),
 ('B', (1.5, 'thanks')),
 ('B', (1.6000000000000001, 'and you')),
 ('A', (1.8999999999999999, "I'm fine")),
 ('C', (2.1200000000000001, 'good')),
 ('C', (2.2400000000000002, 'morning')),
 ('C', (3.1299999999999999, 'guys'))]

Здесь происходит две главные вещи

[(i,k) for i,j in INPUT for k in j]

принимает преобразовывает ВХОД в это будущее

[('A', (0.12, 'how')),
 ('A', (0.26, 'are')),
 ('A', (0.7, 'you')),
 ('A', (0.9, 'mike')),
 ('A', (1.9, "I'm fine")),
 ('B', (1.23, 'fine')),
 ('B', (1.5, 'thanks')),
 ('B', (1.6, 'and you')),
 ('C', (2.12, 'good')),
 ('C', (2.24, 'morning')),
 ('C', (3.13, 'guys'))]

и

sorted(L, key=itemgetter(1))

сортирует L купить элемент [1] каждого элемента. Это на самом деле (0.12, «как»), (0.27, «есть») ... но нормальный способ сортировки кортежей в Python - слева направо, поэтому нам не нужно выполнять дополнительную работу для удаления слова из кортеж

2 голосов
/ 15 февраля 2011

Ваш ввод:

l = [('A',
    [(0.12, 'how'),
    (0.26000000000000001, 'are'),
    (0.69999999999999996, 'you'),
    (0.90000000000000002, 'mike'),
    (1.8999999999999999, "I'm fine too")]),
    ('B', [(1.23, 'fine'), (1.5, 'thanks'), (1.6000000000000001, 'and you')]),
    ('C',
    [(2.1200000000000001, 'good'),
    (2.2400000000000002, 'morning'),
    (3.1299999999999999, 'guys')])]

Преобразование (и печать):

newlist = []
for alpha, tuplelist in l:
    for tup in tuplelist:
        newlist.append((alpha,tup))

from operator import itemgetter
sorted(newlist,key=itemgetter(1))
print newlist

Проверьте!

[('A', (0.12, 'how')),
 ('A', (0.26000000000000001, 'are')),
 ('A', (0.69999999999999996, 'you')),
 ('A', (0.90000000000000002, 'mike')),
 ('B', (1.23, 'fine')),
 ('B', (1.5, 'thanks')),
 ('B', (1.6000000000000001, 'and you')),
 ('A', (1.8999999999999999, "I'm fine too")),
 ('C', (2.1200000000000001, 'good')),
 ('C', (2.2400000000000002, 'morning')),
 ('C', (3.1299999999999999, 'guys'))]

Конечно, вы можете сделать это в пределах понимания списка, но вы все еще используете 2 for петли и 1 встроенную функцию sorted. Тогда сделайте его многословным и читабельным.

2 голосов
/ 15 февраля 2011
data = [(x,id) for (id, xs) in data for x in xs]
data.sort()
for xs,id in data:
    print id,xs


A (0.12, 'how')
A (0.26000000000000001, 'are')
A (0.69999999999999996, 'you')
A (0.90000000000000002, 'mike')
B (1.23, 'fine')
B (1.5, 'thanks')
B (1.6000000000000001, 'and you')
A (1.8999999999999999, "I'm fine too")
C (2.1200000000000001, 'good')
C (2.2400000000000002, 'morning')
C (3.1299999999999999, 'guys')
2 голосов
/ 15 февраля 2011

(ОК, пример данных значительно упрощает описание проблемы. Ответ пересмотрен соответственно)

Шаг 1: уточните описание вашей проблемы путем обратного инжиниринга вашего текущего решения.

  1. Существует 4 различных набора данных, обозначенных A, B, C и D
  2. Эти наборы данных содержатся в серии из двух кортежей формы (ListID, elements)
  3. Каждая запись «elements» сама является списком из двух кортежей формы (индекс, значение)
  4. Пустая запись элементов указывает на конец набора данных
  5. Цель состоит в том, чтобы объединить эти наборы данных в один отсортированный список из двух кортежей (ListID, (index, value)) *

Шаг 2: преобразовать входные данные для создания отдельных записей нужной формы.

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

def get_data(flow, num_data_sets=4):
    finished = set()
    for list_id, elements in flow:
        if list_id in finished:
            continue
        if not elements:
            finished.add(list_id)
            if len(finished) == num_data_sets:
                break
            continue
        for element in elements:
            yield list_id, element

Шаг 3: используйте sorted для получения желаемого упорядоченного списка

content = sorted(get_data(flow))

Пример использования:

# get_data defined via copy/paste of source code above
# ref_data taken from the revised question
>>> demo_data = [
...   ('A', [(1, 2), (3, 4)]),
...   ('B', [(7, 8), (9, 10)]),
...   ('A', [(0, 0)]),
...   ('C', []), # Finish early
...   ('C', [('ignored', 'entry')])
... ]
>>> content = sorted(get_data(demo_data))
>>> print '\n'.join(map(str, content))
('A', 0, 0)
('A', 1, 2)
('A', 3, 4)
('B', 7, 8)
('B', 9, 10)
>>> content = sorted(get_data(ref_data), key=itemgetter(1))
>>> print '\n'.join(map(str, content))
('A', 0.12, 'how')
('A', 0.26, 'are')
('A', 0.7, 'you')
('A', 0.9, 'mike')
('B', 1.23, 'fine')
('B', 1.5, 'thanks')
('B', 1.6, 'and you')
('A', 1.9, "I'm fine too")
('C', 2.12, 'good')
('C', 2.24, 'morning')
('C', 3.13, 'guys')

Ваше решение оказывается грязным и трудным для чтения по двум основным причинам:

  1. Отказ от использования генератора означает, что вы не получаете всех преимуществ встроенной отсортированной функции
  2. Используя индексацию вместо распаковки кортежей, вы очень усложняете отслеживать, что к чему
...