स्मृति कुशल तरीके से एक ही सूची की ओर इशारा करते हुए कई कुंजियों वाला पायथन शब्दकोश


9

मेरी यह अद्वितीय आवश्यकता है जिसे इस कोड द्वारा समझाया जा सकता है। यह काम कर रहा कोड है, लेकिन मेमोरी कुशल नहीं है।

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']

संक्षेप में, मैं चाहता हूं कि उप-सूची के प्रत्येक आइटम को अनुक्रमित किया जाए और सबलिस्ट को वापस कर दिया जाए।

उपरोक्त विधि काम करती है लेकिन डेटा बड़ी होने पर बहुत अधिक मेमोरी लगती है। क्या कोई बेहतर, मेमोरी और सीपीयू अनुकूल तरीका है? डेटा को JSON फ़ाइल के रूप में संग्रहीत किया जाता है।

संपादित करें मैंने सबसे बड़े संभावित उपयोग के मामले के जवाबों की कोशिश की (1000 सबलिस्ट, प्रत्येक सबलिस्ट में 100 आइटम, 1 मिलियन प्रश्न) और यहां परिणाम (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

{item: sublist for sublist in data for item in sublist}थोड़ा और अधिक कुशल और प्रत्यक्ष हो सकता है… ?!
— deceze

हाँ। मेरे नमूना मामले के लिए। मेरे वास्तविक मामले में, सबलिस्ट में 100 आइटम और हजारों ऐसे सबलिस्ट होते हैं। कोड की उपयोगकर्ता को छोटी मेमोरी (<2gb) होती है, इसलिए जब अन्य भारी ऐप चल रहा होता है, तो वे शिकायत करते हैं कि आपकी स्क्रिप्ट धीमी है।
— राहुल

क्या समस्या आप वास्तव में हल करने की कोशिश कर रहे हैं? शायद एक हाइब्रिड दृष्टिकोण काम करेगा, जिसमें आप पहले अक्षर द्वारा अनुक्रमित करते हैं, और फिर अपने सटीक मूल्य को खोजने के लिए कुछ उम्मीदवार सूचियों के माध्यम से पुनरावृति करते हैं, हैश टेबल टकराव संकल्प एल्गोरिथ्म की तरह।
— deceze

कुशल तरीके से उपज () की तरह जनरेटर का उपयोग करें।
— साइसिवा ए

धन्यवाद। मैं सीखूंगा कि "हैश टेबल टक्कर रिज़ॉल्यूशन" का क्या मतलब है।
— राहुल

जवाबों:


2

आप वास्तव में उस समय / स्मृति के बीच एक व्यापार-बंद स्थान पर हैं जो शब्दकोश को उत्पन्न करने में लगने वाले समय को ऑन-द-फ्लाई विधि के लिए संपूर्ण डेटा को स्कैन करने में लेता है।

यदि आप कम मेमोरी विधि चाहते हैं, तो आप एक फ़ंक्शन का उपयोग कर सकते हैं जो प्रत्येक सबलिस्ट को मान के लिए खोजता है। जनरेटर का उपयोग करने से उपयोगकर्ता को प्रारंभिक परिणाम तेजी से मिलेंगे, लेकिन बड़े डेटा सेट के लिए, यह रिटर्न के बीच धीमा होगा।

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 चरित्र के आधार पर एक हैश टेबल का निर्माण शुरू करने के लिए एक अच्छी जगह हो सकती है। यह आपको सब्लिस्ट की एक उम्मीदवार सूची बनाने की अनुमति देगा, फिर उन लोगों को यह देखने के लिए स्कैन करेगा कि क्या मूल्य सूची में है।

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को बनाने में कुछ समय लगेगा, क्योंकि आप अपनी संपूर्ण डेटा संरचना को स्कैन कर रहे हैं। हालाँकि, मेमोरी फ़ुट प्रिंट बहुत छोटा होगा। ट्यूनिंग प्रदर्शन के लिए आप मुख्य पैरामीटर है size। छोटे आकार में एक छोटा मेमोरी फ़ुटप्रिंट होगा, लेकिन इसे चलाते समय अधिक समय लगेगा find_list_by_hashक्योंकि आपका उम्मीदवार पूल बड़ा होगा। आप यह देखने के लिए कुछ परीक्षण कर सकते हैं कि sizeआपके डेटा के लिए क्या अधिकार होना चाहिए। बस इस बात का ध्यान रखें कि आपके सभी मूल्य कम से कम लंबे समय तक हों size।


और मुझे लगा कि मैं अजगर और प्रोग्रामिंग को जानता हूं। धन्यवाद। सीखने के लिए बहुत कुछ है।
— राहुल

2

आप कुछ इस तरह की कोशिश कर सकते हैं:

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

मानचित्रण संरचना बनाने की आवश्यकता नहीं है।


आपको धन्यवाद। अगर यह तेज हो तो मुझे जांच करनी होगी।
— राहुल

1
यह शुरू में बहुत तेज़ होगा क्योंकि गणना करने की कोई समझ नहीं है, लेकिन उपयोग में बहुत धीमा है क्योंकि प्रत्येक तत्व को खोजने के लिए, यह विधि पूरे डेटा को फिर से स्कैन करेगी।
— एडवर्ड थिएल

यकीन है, मुझे पता है अगर यह तुम्हारे लिए काम करता है।
— भूषण पंत

@EdouardThiel: मुझे भी ऐसा ही लगता है। मेरे वास्तविक उपयोग में शुरुआत के मामलों की तुलना में उपयोग के मामले अधिक हैं।
— राहुल

@EdouardThiel सच है। लेकिन मैं सटीक उपयोग के मामले में निश्चित नहीं हूं।
— भूषण पंत

2

पंडों का उपयोग करके यह प्रयास करें

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

यह सरल समाधान दिखता है, भले ही आपका डेटा बड़ा हो, यह कुशलतापूर्वक संभाल लेगा


अपने आकार की जाँच करें df: यह दी गई उदाहरण डेटा के लिए सूची data(> x12) और तानाशाही temp_dict(~ x2) की तुलना में काफी बड़ा है - बिल्कुल नहीं स्मृति-कुशल मैं कहूंगा
— MrFuppes

@ मुझे लगता है कि मुझे नहीं लगता कि यह तर्क मान्य है, क्योंकि पांडा इस मामले में शारीरिक रूप से नकल नहीं करते हैं
— mcsoini

@mcsoini, मैं स्वीकार करता हूं कि मेरी टिप्पणी थोड़ी सतही है - pandasयह निर्धारित करने के लिए कि यदि इस समस्या को अधिक से अधिक अजगर कार्यक्षमता से अधिक कुशल संभालता है, तो एक और अलग विश्लेषण करना आवश्यक होगा ।
— MrFuppes

@ मेरीफुप्स: मैं सहमत हूं। pandasयदि इसका उपयोग किया जा सकता है तो उपयोग क्यों करें stdlib। सिर्फ इसलिए कि यह फैंसी लग रहा है?
— राहुल

1
लेकिन आपने यह नहीं बताया कि मैं डेटाफ्रेम को कैसे क्वेरी करूंगा। क्या आप मुझे दिखा सकते हैं कि कैसे आपका समाधान मेरी समस्या का समाधान करेगा। मैंने पंडों के लिए @ mcsoini के समाधान की कोशिश की, लेकिन यह 1 मिलियन प्रश्नों के लिए हमेशा के लिए ले रहा है। मुझे पता नहीं क्यों। विभिन्न तरीकों के परिणामों के लिए कृपया मेरा अद्यतन प्रश्न देखें।
— राहुल

0

मुझे पूरी तरह से यकीन नहीं है कि यह बड़ी मात्रा में डेटा के लिए कैसे व्यवहार करेगा, लेकिन आप की तर्ज पर कुछ कोशिश कर सकते हैं:

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

संपादित करें: कुछ नकली बड़े पैमाने पर डेटा के साथ त्वरित परीक्षण के आधार पर, समय के संदर्भ में फायदेमंद नहीं लगता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.