Сортировка и группировка вложенных списков в Python
У меня есть следующая структура данных (список списков)
[
['4', '21', '1', '14', '2008-10-24 15:42:58'],
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
]
Я хотел бы иметь возможность
-
Используйте функцию для изменения порядка списка, чтобы я мог группироваться по каждому элементу в списке. Например, я хотел бы иметь возможность группировать второй столбец (чтобы все 21 были вместе)
-
Используйте функцию для отображения только определенных значений из каждого внутреннего списка. Например, я хотел бы уменьшить этот список, чтобы содержать только четвертое значение поля '2somename'
чтобы список выглядел следующим образом:
[
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
]
Ответы
Ответ 1
Для первого вопроса первое, что вам нужно сделать, это отсортировать список по второму полю:
x = [
['4', '21', '1', '14', '2008-10-24 15:42:58'],
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
]
from operator import itemgetter
x.sort(key=itemgetter(1))
Затем вы можете использовать функцию groupby для itertools:
from itertools import groupby
y = groupby(x, itemgetter(1))
Теперь y является итератором, содержащим кортежи (element, item iterator). Это более запутанно объяснять эти кортежи, чем показывать код:
for elt, items in groupby(x, itemgetter(1)):
print(elt, items)
for i in items:
print(i)
Какие принты:
21 <itertools._grouper object at 0x511a0>
['4', '21', '1', '14', '2008-10-24 15:42:58']
['5', '21', '3', '19', '2008-10-24 15:45:45']
['6', '21', '1', '1somename', '2008-10-24 15:45:49']
22 <itertools._grouper object at 0x51170>
['3', '22', '4', '2somename', '2008-10-24 15:22:03']
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
Во второй части вы должны использовать списки, как уже упоминалось здесь:
from pprint import pprint as pp
pp([y for y in x if y[3] == '2somename'])
Какие принты:
[['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']]
Ответ 2
Если вы назначили его var "a"...
# 1:
a.sort(lambda x,y: cmp(x[1], y[1]))
# 2:
filter(lambda x: x[3]=="2somename", a)
Ответ 3
Если я правильно понял ваш вопрос, следующий код должен выполнить следующее задание:
l = [
['4', '21', '1', '14', '2008-10-24 15:42:58'],
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
]
def compareField(field):
def c(l1,l2):
return cmp(l1[field], l2[field])
return c
# Use compareField(1) as the ordering criterion, i.e. sort only with
# respect to the 2nd field
l.sort(compareField(1))
for row in l: print row
print
# Select only those sublists for which 4th field=='2somename'
l2somename = [row for row in l if row[3]=='2somename']
for row in l2somename: print row
Вывод:
['4', '21', '1', '14', '2008-10-24 15:42:58']
['5', '21', '3', '19', '2008-10-24 15:45:45']
['6', '21', '1', '1somename', '2008-10-24 15:45:49']
['3', '22', '4', '2somename', '2008-10-24 15:22:03']
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
['3', '22', '4', '2somename', '2008-10-24 15:22:03']
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
Ответ 4
Используйте функцию для изменения порядка списка, чтобы я мог группировать по каждому элементу в списке. Например, я хотел бы иметь возможность группировать второй столбец (чтобы все 21 были вместе)
Списки имеют встроенный метод сортировки, и вы можете предоставить функцию, которая извлекает ключ сортировки.
>>> import pprint
>>> l.sort(key = lambda ll: ll[1])
>>> pprint.pprint(l)
[['4', '21', '1', '14', '2008-10-24 15:42:58'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']]
Используйте функцию для отображения только определенных значений из каждого внутреннего списка. Например, я хотел бы уменьшить этот список, чтобы содержать только 4-е значение поля "2somename"
Это выглядит как работа для понимания списка
>>> [ll[3] for ll in l]
['14', '2somename', '19', '1somename', '2somename']
Ответ 5
Если вы будете много сортировать и фильтровать, вам могут понравиться некоторые вспомогательные функции.
m = [
['4', '21', '1', '14', '2008-10-24 15:42:58'],
['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']
]
# Sort and filter helpers.
sort_on = lambda pos: lambda x: x[pos]
filter_on = lambda pos,val: lambda l: l[pos] == val
# Sort by second column
m = sorted(m, key=sort_on(1))
# Filter on 4th column, where value = '2somename'
m = filter(filter_on(3,'2somename'),m)
Ответ 6
Для части (2), когда x является вашим массивом, я думаю, что вы хотите,
[y for y in x if y[3] == '2somename']
Будет возвращен список только ваших списков данных, у четвертого значения будет "2somename"... Хотя кажется, что Kamil дает вам лучший совет по переходу на SQL...
Ответ 7
Это похоже на то, что вы пытаетесь использовать список в качестве базы данных.
В настоящее время Python включает в себя SQL-привязки в основном дистрибутиве. Если вам не нужна настойчивость, очень просто создать базу данных sqlite в памяти (см. Как создать базу данных sqlite3 в памяти?).
Затем вы можете использовать операторы SQL для выполнения всей этой сортировки и фильтрации без необходимости изобретать колесо.
Ответ 8
Вы просто создаете индексы в своей структуре, не так ли?
>>> from collections import defaultdict
>>> def indexOn( things, pos ):
... inx= defaultdict(list)
... for t in things:
... inx[t[pos]].append(t)
... return inx
...
>>> a=[
... ['4', '21', '1', '14', '2008-10-24 15:42:58'],
... ['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
... ['5', '21', '3', '19', '2008-10-24 15:45:45'],
... ['6', '21', '1', '1somename', '2008-10-24 15:45:49'],
... ['7', '22', '3', '2somename', '2008-10-24 15:45:51']
... ]
Вот ваш первый запрос, сгруппированный по позиции 1.
>>> import pprint
>>> pprint.pprint( dict(indexOn(a,1)) )
{'21': [['4', '21', '1', '14', '2008-10-24 15:42:58'],
['5', '21', '3', '19', '2008-10-24 15:45:45'],
['6', '21', '1', '1somename', '2008-10-24 15:45:49']],
'22': [['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']]}
Вот ваш второй запрос, сгруппированный по позиции 3.
>>> dict(indexOn(a,3))
{'19': [['5', '21', '3', '19', '2008-10-24 15:45:45']], '14': [['4', '21', '1', '14', '2008-10-24 15:42:58']], '2somename': [['3', '22', '4', '2somename', '2008-10-24 15:22:03'], ['7', '22', '3', '2somename', '2008-10-24 15:45:51']], '1somename': [['6', '21', '1', '1somename', '2008-10-24 15:45:49']]}
>>> pprint.pprint(_)
{'14': [['4', '21', '1', '14', '2008-10-24 15:42:58']],
'19': [['5', '21', '3', '19', '2008-10-24 15:45:45']],
'1somename': [['6', '21', '1', '1somename', '2008-10-24 15:45:49']],
'2somename': [['3', '22', '4', '2somename', '2008-10-24 15:22:03'],
['7', '22', '3', '2somename', '2008-10-24 15:45:51']]}