2013-08-01 121 views
1

有沒有一種方法可以隨機洗牌什麼鍵對應什麼值?我發現random.sample,但我想知道是否有更pythonic /更快的方式做到這一點。在Python中隨機隨機洗牌的鍵和值DIctionary

例子:a = {"one":1,"two":2,"three":3}

拋去:a_shuffled = {"one":2,"two":3,"three":1}

+1

我不想重新排序的解釋,我想將它洗這樣的關鍵將指向一個不同的值。看我的例子。 – brebs

+0

對,您可能希望對此更加明確;乍看之下,您的問題看起來像是有關訂購和字典的另一個問題。 –

回答

2

對不起,使其更快的唯一方法是使用numpy的:/。 不管你做什麼,它都會以某種方式爭奪所有需要時間的指數 - 所以在C中這樣做會有所幫助。此外,純粹的隨機和隨機的區別在於你不能有重複的指數。

對不起這有點長了 - 所以你必須做一些滾動

E.g.                                    


# made for python 2.7 but should be able to work in python 3 
import random 
import numpy as np 
from time import time 


def given_seq(): 
#general example 
    start = time() 
    a = {"one":1,"two":2,"three":3} 
    keys = a.keys() 
    random.shuffle(keys) 
    a = dict(zip(keys, a.values())) 

#Large example 

a = dict(zip(range(0,100000), range(1,100001))) 

def random_shuffle(): 
    keys = a.keys() 
    random.shuffle(keys) 
    b = dict(zip(keys, a.values())) 

def np_random_shuffle(): 
    keys = a.keys() 
    np.random.shuffle(keys) 
    b = dict(zip(keys, a.values())) 

def np_random_permutation(): 
    #more concise and using numpy's permutation option 
    b = dict(zip(np.random.permutation(a.keys()), a.values())) 

#if you precompute the array key as a numpy array 

def np_random_keys_choice(): 
    akeys = np.array(a.keys()) 
    return dict(zip(akeys[np.random.permutation(len(akeys))],a.values())) 

def np_random_keys_shuffle(): 
    key_indexes = np.arange(len(a.keys())) 
    np.random.shuffle(key_indexes) 
    return dict(zip(np.array(a.keys())[key_indexes],a.values())) 

#fixed dictionary size 
key_indexes = np.arange(len(a.keys())) 
def np_random_fixed_keys_shuffle(): 
    np.random.shuffle(key_indexes) 
    return dict(zip(np.array(a.keys())[key_indexes],a.values())) 


#so dstack actually slows things down 
def np_random_shuffle_dstack(): 
    keys = a.keys() 
    np.random.shuffle(keys) 
    return dict(np.dstack((keys, a.values()))[0]) 

if __name__=='__main__': 
    import timeit 
    # i can use global namespace level introspection to automate the below line but it's not needed yet 
    for func in ['given_seq', 'random_shuffle', 'np_random_shuffle', 'np_random_permutation', 'np_random_keys_choice', 
      'np_random_keys_shuffle', 'np_random_fixed_keys_shuffle']: 
     print func, timeit.timeit("{}()".format(func), setup = "from __main__ import {}".format(''.join(func)), number = 200) 
given_seq 0.00103783607483 
random_shuffle 23.869166851 
np_random_shuffle 16.3060112 
np_random_permutation 21.9921720028 
np_random_keys_choice 21.8105020523 
np_random_keys_shuffle 22.4905178547 
np_random_fixed_keys_shuffle 21.8256559372 

使用選擇/置換看起來更好 - 但它不以任何方式更快。不幸的是,複製通常是緩慢的,除非它是一個小尺寸 - 並且沒有辦法通過指針/引用,而不必佔用額外的行 - 儘管我辯論如果這使得它'非pythonic'

即如果你看在Zen of Python或只是做import this在蟒蛇會議的行之一是:

儘管實用性勝過純度。

所以它的開放當然:)

+0

由於某種原因,當我在諸如a.keys()的列表上使用np.random.shuffle時,它返回一個'NoneType'類型的對象。這顯然然後失敗時,我拉鍊。當我使用random.shuffle時也是如此。想法? – brebs

+0

''np.random.shuffle''洗滌一個物體到位。在我看來,它是在後臺搞定指針,所以它不會給你一個對象,因爲它從不復制它:) - 只用指針玩就更快,因爲一個巨型數組可以有幾百萬個整數,而一個指針和一個長度/結束指針的大小減去 –

+0

謝謝!我試圖將它保存爲一個新的變量。我沒有意識到它只是洗了原來的東西。它現在有效。 – brebs

6
In [47]: import random 

In [48]: keys = a.keys() 

In [49]: values = a.values() 

In [50]: random.shuffle(values) 

In [51]: a_shuffled = dict(zip(keys, values)) 

In [52]: a_shuffled 
Out[52]: {'one': 2, 'three': 1, 'two': 3} 

,或者更簡練是:

In [56]: dict(zip(a.keys(), random.sample(a.values(), len(a)))) 
Out[56]: {'one': 3, 'three': 2, 'two': 1} 

(但我想那就是你已經想出瞭解決方案)


注意,雖然使用random.sample是pithier,使用random.shuffle是快了一點:

import random 
import string 
def using_shuffle(a): 
    keys = a.keys() 
    values = a.values() 
    random.shuffle(values) 
    return dict(zip(keys, values)) 

def using_sample(a): 
    return dict(zip(a.keys(), random.sample(a.values(), len(a)))) 

N = 10000 
keys = [''.join(random.choice(string.letters) for j in range(4)) for i in xrange(N)] 
a = dict(zip(keys, range(N))) 

In [71]: %timeit using_shuffle(a) 
100 loops, best of 3: 5.14 ms per loop 

In [72]: %timeit using_sample(a) 
100 loops, best of 3: 5.78 ms per loop