2011-12-01 10 views
8

टीएलिस्ट से हटाएं (0) में टीएलिस्ट की शुरुआत से आइटमों का एक बड़ा ब्लॉक हटाने का एक प्रभावी तरीका महंगा है क्योंकि सभी बाद के आइटमों को स्थानांतरित करने की आवश्यकता है। अगर मुझे एक बड़ी सूची की शुरुआत से बड़ी संख्या में आइटम हटाना होगा तो सबसे तेज़ तरीका क्या है?डेल्फी

+0

क्या आप सुनिश्चित हैं कि बाद के आइटमों को स्थानांतरित करने की आवश्यकता है .. यदि यह एक लिंक्ड सूची के रूप में लागू किया गया है तो यह काफी चीप है। यह नहीं कि यह टिप्पणी प्रश्न के लिए वैध उत्तर प्राप्त करने की आवश्यकता को हटा देती है .. – baash05

+0

क्या हटाने के बाद वस्तुओं का क्रम क्या है? –

+1

@ baash05: मेरा मानना ​​है कि टीएलिस्ट को एक सरणी के रूप में लागू किया गया है। –

उत्तर

8

TList की शुरुआत से तत्वों की एक बड़ी श्रृंखला को हटाना महंगा है। यद्यपि कक्षा का नाम धोखा देने के लिए flatters, TList वास्तव में एक सरणी है। TList में कोई सीमा हटाने की कोई सुविधा नहीं है- प्रत्येक आइटम को व्यक्तिगत रूप से हटा दिया जाना चाहिए और फिर बाकी की सूची नीचे ले जाया गया है। एक बड़ी श्रृंखला के लिए जो एक बहुत सारे पुनर्विक्रय और पूर्ण सूची चाल को उकसाएगा।

यदि आपके पास अधिक आधुनिक डेल्फी था तो आप सामान्य सूची वर्ग TList<T> का उपयोग कर सकते हैं और DeleteRange विधि का लाभ उठा सकते हैं। दस्तावेज़ीकरण में यह महत्वपूर्ण नोट शामिल है:

यह एक ओ (ACount) ऑपरेशन है।

डेल्फी 2006 में आप इस तरह बराबर प्रदर्शन विशेषताओं के साथ कुछ लिख सकते हैं:

procedure DeleteRange(List: TList; AIndex, ACount: Integer); 
var 
    i: Integer; 
    NewCount: Integer; 
begin 
    NewCount := List.Count-ACount; 
    Assert(AIndex>=0); 
    Assert(ACount>=0); 
    Assert(NewCount>=0); 
    for i := AIndex to NewCount-1 do 
    List[i] := List[i+ACount] 
    List.Count := NewCount; 
end; 
+0

+1। अच्छा जवाब, और डी 2006 समकक्ष के साथ अच्छा जोड़ा। –

+0

इतना अच्छा नहीं है। अनुमान लगाएं [TList.Count] (http://docwiki.embarcadero.com/VCL/en/Classes.TList.Count) संपत्ति सेटटर करते हैं। यह आंतरिक रूप से [TList.Delete] (http://docwiki.embarcadero.com/VCL/en/Classes.TList.Delete) को पुराने मान से नए मान में पुनरावृत्ति में कॉल करता है। तो कोई प्रदर्शन वृद्धि नहीं है। और, डेविड, [TList.Notify] के बारे में नोट (http://docwiki.embarcadero.com/VCL/en/Classes.TList.Notify), आप आंतरिक [TList.Delete] के बाद भी इसे प्राप्त करेंगे (http: //docwiki.embarcadero.com/VCL/en/Classes.TList.Delete) कॉल करता है। – TLama

+0

@TLama मेरे डेल्फी के पास एक कुशल सेटकाउंट है। आप किस संस्करण को देख रहे हैं? वही है, अंत में हटाना सस्ता है जब क्षमता नहीं बदली जाती है। स्पष्ट होने के लिए, हटाएं (गणना -1) हटाएं (0) से पूरी तरह से अलग है। –

0

सबसे पहले, प्रत्येक आइटम को हटाकर टीएलआईस्ट के यूआई को अपडेट करने से रोकने के लिए BeginUpdate और EndUpdate का उपयोग करें।

दूसरा: सबसे पहले सूची में सबसे कम आइटम को हटाने का प्रयास करें। दूसरे शब्दों में, सूची से ऊपर तक की वस्तुओं को हटाने से अन्य वस्तुओं पर कम कुशलता मिलती है। ,

for I := 0 to List.Count - N - 1 do 
    list[I] := list[I + N]; 
for I := list.Count - 1 downto list.Count - N do 
    list.Delete(I) 

मैं बहुत अच्छी तरह से के माध्यम से इस कोड में नहीं सोचा तो आप बंद-एक करके जांच करने के लिए की आवश्यकता होगी:

+3

TList पर कोई 'BeginUpdate' या' EndUpdate' नहीं है। –

+0

कोई भी "टीएलआईस्ट का यूआई" नहीं है; 'TList' एक ग्राफिक घटक नहीं है। और मुझे पूरा यकीन नहीं है कि दूसरा अनुच्छेद क्या कहता है - क्या आप अपना उत्तर संपादित कर सकते हैं? –

1

तो आदेश मामलों, और आप मोर्चे पर दूर करने के लिए एन आइटम नहीं हैं त्रुटियों और पसंद है।

यदि ऑर्डर कोई फर्क नहीं पड़ता है, तो आप पहले एन आइटम को पहले एन आइटम के साथ एक्सचेंज कर सकते हैं और उपरोक्त अंतिम एन आइटम को हटा सकते हैं।

+0

हटाने का आदेश कोई फर्क नहीं पड़ता। क्या आप एक टीएलआईस्ट के लिए "सेट लम्बाई" कर सकते हैं? - यह हटाएं एन बार कॉल करने से तेज़ होगा। – rossmcm

+0

@ross हाँ आप कर सकते हैं। आप बस 'List.Count: = ...' –

+0

+1 यह एक अच्छा जवाब है, लेकिन इसे सूची के उपयोग के साथ शीर्ष पर रखा जाएगा। काउंटर –

4

मार्सेलो जैसा कि पहले ही कहा, आप के बजाय आइटम करके उस आइटम कर के पूरे ब्लॉक नीचे नकल कर सकता है, लेकिन, आप तर्क के रूप में TList.List का उपयोग करके, एक कॉल को मूव() में ले जाया जा सकता है।

ध्यान दें कि TList.List था एक PPointerList (^TPointerList; TPointerList = array[0..MaxListSize - 1] of Pointer;) पुराने डेल्फी संस्करणों में और बन गया एक TPointerList (TPointerList = array of Pointer;) डेल्फी XE2 में है, तो आप सही अविवेक का उपयोग करना चाहिए:

TList(aList).List^[index] // for older Delphi's 

और

TList(aList).List[index] // for Delphi XE2 
+1

वह 'TList.Notify' को विचलित कर देगा, लेकिन इससे कोई फर्क नहीं पड़ता –

+1

अभी भी, यह अतिरिक्त जटिलता को न्यायसंगत बनाने के लिए पर्याप्त तेज़ हो सकता है। – afrazier

2

यहां आप XE2 में ऐसा कैसे करते हैं, क्योंकि टीएलिस्ट पॉइंटर्स की एक सरणी है।

कार्यान्वयन डेल्फी 2006 को समान होगा, लेकिन जब से मैं संकेत बिंदु स्मृति में कामयाब रहे हैं करने के लिए चीजों के सभी के रूप में जब तक 2006.

// I have 1000000 items, and I want to delete the first 5000 
// Copy the pointer array items up the array 
CopyMemory(@myList.List[0], 
    @myList.List[5000], 
    SizeOf(Pointer) * (myList.Count - 5000)); 
// Reset the count. Delphi cooperates as long as we're shrinking 
myList.Count := myList.Count - 5000; 
// You now have tons of unused memory at the end, it's fine 
// but if you want to clean house 
myList.Capacity := myList.Count; 

की जरूरत नहीं है मैं कोड नहीं लिख सकते हैं कहीं और, कोई रिसाव नहीं है।

यहाँ सबूत है:

type 
    TMyObject = class 
    index: Integer; 
    end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    myList: TList; 
    i: Integer; 
    myObject: TMyObject; 
begin 
    // Create a list with 1000000 entries 
    myList := TList.Create; 
    for i := 1 to 1000000 do 
    begin 
    myObject := TMyObject.Create; 
    myObject.index := i; 
    myList.Add(myObject); 
    end; 
    // Delete the first 5000 
    CopyMemory(@myList.List[0], 
    @myList.List[5000], 
    SizeOf(Pointer) * (myList.Count - 5000)); 
    myList.Count := myList.Count - 5000; 
    myList.Capacity := myList.Count; 
    // Show the new count 
    ShowMessage(IntToStr(myList.Count)); 
    // Shows that my array now has objects 5001 and up 
    for i := 0 to 5 do 
    begin 
    myObject := TMyObject(myList.Items[i]); 
    ShowMessage(IntToStr(myObject.index)); 
    end; 
end; 

सबूत प्रमुख मेमोरी लीक है, लेकिन हम अभी मान दिखाने के लिए ऑब्जेक्ट का निर्माण होगा।

+1

मुझे लगता है कि उपरोक्त को अपनी कक्षा के तरीके के रूप में लागू करने वाली अपनी टीएलआईस्ट कक्षा बहुत अच्छी होगी। –

1

यहां एक विचार है: यदि आपको पता है कि आपकी सूची में सभी आइटम असाइन किए गए हैं, तो आप उन लोगों को निपटा सकते हैं जिन्हें आप निकालना चाहते हैं और बस TList.Pack() को कॉल करें, जो आंकड़े बताते हैं कि रिक्त स्थान कहां हैं और बाकी सब कुछ एक तरफ ले जाते हैं यथासंभव कुशलतापूर्वक। इसके लिए सभी वस्तुओं के माध्यम से स्कैन की आवश्यकता होती है, इसलिए हो सकता है कि आप जो भी चाहते हों, हो लेकिन यह हटाएं (और इस प्रकार नाइटोफी कॉल को रोकता है) का उपयोग नहीं करता है। पैक का कार्यान्वयन डी 2006 और एक्सई 2 के बीच थोड़ा सा नहीं बदला है, इसलिए आप इसकी दक्षता पर निर्भर कर सकते हैं।

नोट, कि जिन वस्तुओं को आप निकालना चाहते हैं उन्हें शून्य करने के लिए, आप List[aIndex] := nil का उपयोग कर सकते हैं लेकिन यह अभी भी एक नोटिफ़ाई() कॉल लगाएगा, इसलिए List.List[aIndex] := nil इसके लिए तेज़ हो सकता है।