簡體   English   中英

Python 字典,多個鍵指向 memory 有效方式中的同一列表

[英]Python dictionary with multiple keys pointing to same list in memory efficient way

我有這個獨特的要求,可以用這段代碼來解釋。 這是有效的代碼,但 memory 效率不高。

data = [[
        "A 5408599",
        "B 8126880",
        "A 2003529",
    ],
    [
        "C 9925336",
        "C 3705674",
        "A 823678571",
        "C 3205170186",
    ],
    [
        "C 9772980",
        "B 8960327",
        "C 4185139021",
        "D 1226285245",
        "C 2523866271",
        "D 2940954504",
        "D 5083193",
    ]]

temp_dict = {
    item: index for index, sublist in enumerate(data)
        for item in sublist
}

print(data[temp_dict["A 2003529"]])

out: ['A 5408599', 'B 8126880', 'A 2003529']

簡而言之,我希望子列表的每個項目都是可索引的,並且應該返回子列表。

上述方法有效,但是當數據很大時,它需要大量的 memory。 有沒有更好的 memory 和 CPU 友好的方式? 數據存儲為 JSON 文件。

編輯我嘗試了最大可能用例場景的答案(1000 個子列表,每個子列表中有 100 個項目,100 萬個查詢),這里是結果(10 次運行的平均值):

Method,    Time (seconds),    Extra Memory used
my,        0.637              40 Mb
deceze,    0.63               40 Mb
James,     0.78               200 kb
Pant,      > 300              0 kb
mcsoini,   forever            0 kb

你可以嘗試這樣的事情:

list(filter(lambda x: any(["C 9772980" in x]),data))

無需制作映射結構。

您實際上是在生成字典所需的時間/內存與掃描整個數據以查找動態方法所需的時間之間進行權衡。

如果您想要一個低 memory 方法,您可以使用 function 搜索每個子列表的值。 使用生成器將更快地為用戶獲得初始結果,但對於大型數據集,這在返回之間會很慢。

data = [[
        "A 5408599",
        "B 8126880",
        "A 2003529",
    ],
    [
        "C 9925336",
        "C 3705674",
        "A 823678571",
        "C 3205170186",
    ],
    [
        "C 9772980",
        "B 8960327",
        "C 4185139021",
        "D 1226285245",
        "C 2523866271",
        "D 2940954504",
        "D 5083193",
    ]]


def find_list_by_value(v, data):
    for sublist in data:
        if v in sublist:
            yield sublist

for s in find_list_by_value("C 9772980", data):
    print(s)

如評論中所述,僅基於第一個字母或前 2 或 3 個字符構建 hash 表可能是一個不錯的起點。 這將允許您構建子列表的候選列表,然后掃描它們以查看該值是否在子列表中。

from collections import defaultdict

def get_key(v, size=3):
    return v[:size]

def get_keys(sublist, size=3):
    return set(get_key(v, size) for v in sublist)

def find_list_by_hash(v, data, hash_table, size=3):
    key = get_key(v, size)
    candidate_indices = hash_table.get(key, set())
    for ix in candidates:
        if v in data[ix]:
            yield data[ix]

# generate the small hash table
quick_hash = defaultdict(set)
for i, sublist in enumerate(data):
    for k in get_keys(sublist, 3):
        quick_hash[k].add(i)

# lookup a value by the small hash
for s in find_list_by_hash("C 9772980", data, quick_hash, 3):
    print(s)

在此代碼quick_hash需要一些時間來構建,因為您正在掃描整個數據結構。 但是,memory 占用空間會小很多。 您調整性能的主要參數是size 較小的尺寸將具有較小的 memory 占用空間,但在運行find_list_by_hash時會花費更長的時間,因為您的候選池會更大。 您可以進行一些測試以查看適合您的數據的size 請注意,您的所有值都至少size一樣長。

試試這個,使用 pandas

import pandas as pd
df=pd.DataFrame(data)
rows = df.shape[0]
for row in range(rows):
    print[[row]]    #Do something with your data

這看起來很簡單的解決方案,即使您的數據變大,這也會有效地處理

我不完全確定這對於大量數據會如何表現,但您可以嘗試以下方式:

import pandas as pd
df = pd.DataFrame(data).T
df.loc[:, (df == 'A 2003529').any(axis=0)]
Out[39]: 
           0
0  A 5408599
1  B 8126880
2  A 2003529
3       None
4       None
5       None
6       None

編輯:基於對一些假的更大規模數據的快速測試,在時間方面似乎沒有好處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM