2015-04-30 4 views
-1

У меня есть более 9000 атрибутов данных в словаре. Простая версия выглядит так:Сортировка значений списка в словаре

test = {1092268: [81, 90], 524292: [80, 80], 892456: [88, 88]} 

Это идентификаторы генов с двумя значениями внутри списка. Я хочу, чтобы в итоге появилось несколько словарей, содержащих все идентификаторы со значениями выше или ниже определенного значения. Таким образом, в этом примере можно сказать, что я хочу, чтобы в итоге было три словаря: один содержит идентификаторы и значения, которые находятся ниже 85, а остальные - выше 85, а последние - с первым значением под 85 и вторым выше 85. Поэтому я бы в конечном итоге с этим:

testabove = { 892456: [88, 88]} 

и

testbelow = { 524292: [80, 80]} 

и

testboth = { {1092268: [81, 90]} 

Я понятия не имею, как это цифра.

ответ

5

Это просто сделать это с помощью словаря понимания

>>> testabove = {i:j for i,j in test.items() if j[0]>85 and j[1] > 85} 
>>> testbelow = {i:j for i,j in test.items() if j[0]<85 and j[1] < 85} 
>>> testboth = {i:j for i,j in test.items() if i not in testabove and i not in testbelow} 
>>> testabove 
{892456: [88, 88]} 
>>> testbelow 
{524292: [80, 80]} 
>>> testboth 
{1092268: [81, 90]} 

Как Marein упоминается ниже в comments, другой способ сделать это

>>> test = {1092268: [81, 90], 524292: [80, 80], 892456: [88, 88]} 
>>> testabove = {i:j for i,j in test.items() if all(x>85 for x in j)} 
>>> testbelow = {i:j for i,j in test.items() if all(x<85 for x in j)} 
>>> testabove 
{892456: [88, 88]} 
>>> testbelow 
{524292: [80, 80]} 

Это использует all функцию

Сравнение

$ python -m timeit "test = {1092268: [81, 90], 524292: [80, 80], 892456: [88, 88]};testabove = {i:j for i,j in test.items() if all(x>85 for x in j)}" 
100000 loops, best of 3: 2.29 usec per loop 
$ python -m timeit "test = {1092268: [81, 90], 524292: [80, 80], 892456: [88, 88]};testabove = {i:j for i,j in test.items() if j[0]>85 and j[1] > 85}" 
1000000 loops, best of 3: 0.99 usec per loop 

Как вы можете видеть, прямой путь быстрее, чем при использовании all.

+3

Вы можете использовать 'min (j)> 85' в качестве условия для' testabove' и аналогичного для 'testbelow'. Или, возможно, «все (x> 85 для x в j)», что быстрее в отрицательном случае. – Marein

+0

@Marein Я думаю, что простой способ является лучшим, потому что он требует меньше объяснений :) Но да, это хорошая идея. Спасибо –

+0

@Marein: Хорошие идеи. Хотя «короткое замыкание» на основе «все» я подозреваю, что мин/макс будет быстрее, так как они работают на скорости C. Кто-нибудь хочет сделать несколько тестов timeit ...? –

0

Существует два основных варианта. Один, если вам нужен итеративный и один, если вам нужна более постоянная структура данных. Более постоянное решение состоит в том, чтобы инициализировать все три целевых словаря, затем перебирать исходный dict и сортировать их там, где это необходимо.

target_dicts = {'aboveabove':{}, 'belowbelow':{}, 'belowabove':{}} 
for k,v in src_dict.items(): 
    first = 'above' if v[0] > 85 else 'below' 
    second = 'above' if v[1] > 85 else 'below' 
    result = first+second # 'aboveabove', 'belowbelow', etc... 
    if result in target_dicts: 
     target_dicts[result][k] = v 

Это заполнит ваши target_dicts словари надлежащим образом. Но, может быть, вам не нужно использовать их все? Вам может понадобиться только итератор, а не перестраивать их в памяти. Давайте вместо этого используем фильтр!

target_iterators = { 
    'aboveabove': filter(
     lambda k: all(v > 85 for v in src_dict[k]), src_dict), 
    'belowbelow': filter(
     lambda k: all(v <= 85 for v in src_dict[k]), src_dict), 
    'belowabove': filter(
     lambda k: src_dict[k][0] <= 85 and src_dict[k][1] > 85, src_dict)} 
1

Вот еще одно решение, которое должно быть быстрее для большого количества данных, так как он строит все три словарей в одной итерации.

def compare_both(xs,pivot): 
if xs[0] < pivot and xs[1] < pivot: return -1 
if xs[0] > pivot and xs[1] > pivot: return 1 
return 0 

def sort_dict(d,pivot): 
    dicts = [{},{},{}] 
    for key,value in d.items(): 
    dicts[compare_both(value,pivot)+1][key] = value 
    return dicts 
1

Прямодушное решение:

tmp = testboth, testabove, testbelow = {}, {}, {} 
for k, v in test.items(): 
    tmp[(v[0] > 85 < v[1]) - (v[0] <85> v[1])][k] = v 

Это также быстрее, чем решение Bhargav в, судя по тестам со случайным входом соответствующего размера. Испытание и результаты:

from random import * 
test = {key: [randrange(170), randrange(170)] for key in sample(range(10000000), 9500)} 
from timeit import timeit 
print 'Bhargav', timeit(lambda: Bhargav(), number=100) 
print 'Stefan', timeit(lambda: Stefan(), number=100) 

Bhargav 1.87454111948 
Stefan 1.2636884789 

Еще два варианта, не уверенный, что мне больше всего нравится.

testboth, testabove, testbelow = tmp = {}, {}, {} 
for k, (a, b) in test.items(): 
    tmp[(a > 85 < b) - (a <85> b)][k] = [a, b] 

for k, v in test.items(): 
    a, b = v 
    tmp[(a > 85 < b) - (a <85> b)][k] = v 

Сроки для них примерно 1,7 и 1,2 секунды.

Смежные вопросы