2008-09-03 19 views
29

कहें कि मेरे पास रिकॉर्ड्स में से किसी एक फ़ील्ड के आधार पर सॉर्ट करना चाहते हैं। इसे प्राप्त करने का सबसे अच्छा तरीका क्या है?सरणी को सॉर्ट करने का सबसे अच्छा तरीका

TExample = record 
    SortOrder : integer; 
    SomethingElse : string; 
end; 

var SomeVar : array of TExample; 
+0

बस इस व्यायाम के माध्यम से चला गया और पाया सबसे अच्छा तरीका है अपने खुद के कोड लिखने के लिए है। मुझे नहीं लगता कि किसी भी उत्तर की सिफारिश ** ** के रूप में की जानी चाहिए। – Sam

+0

प्वाइंट लिया गया। हो सकता है कि आप समस्या के समाधान के साथ भी एक उत्तर जोड़ सकें? – Marius

+0

जूलियन बकनेल द्वारा डेल्फी एल्गोरिदम और डेटा संरचनाओं के टॉमस में कुछ अच्छी जानकारी है। (एस –

उत्तर

31

आप एरे के तत्वों को TList पर पॉइंटर्स जोड़ सकते हैं, फिर तुलनात्मक फ़ंक्शन के साथ TList.Sort पर कॉल करें, और अंत में एक नई सरणी बनाएं और वांछित क्रम में TList से मानों की प्रतिलिपि बनाएँ।

हालांकि, यदि आप अगले संस्करण, डी 200 9 का उपयोग कर रहे हैं, तो वहां एक नया संग्रह लाइब्रेरी है जो सरणी को सॉर्ट कर सकती है। कस्टम सॉर्टिंग ऑर्डर के लिए यह वैकल्पिक IComparer<TExample> कार्यान्वयन लेता है। यहाँ यह अपने विशिष्ट मामले के लिए कार्रवाई में है:

TArray.Sort<TExample>(SomeVar , TDelegatedComparer<TExample>.Construct(
    function(const Left, Right: TExample): Integer 
    begin 
    Result := TComparer<Integer>.Default.Compare(Left.SortOrder, Right.SortOrder); 
    end)); 
+1

ध्यान दें कि डी 200 9 में जेनरिक के साथ कंपाइलर में कई मुद्दे हैं, इसलिए संग्रह लाइब्रेरी का उपयोग कभी भी एक अच्छा विकल्प नहीं है (नकली कंपाइलर आंतरिक त्रुटियों और कोडेजन त्रुटियों के कारण) डेल्फी XE में उन मुद्दों अधिकांश भाग के लिए हल किया गया है, यद्यपि जेनेरिक संस्करणों का उपयोग करने में प्रदर्शन हिट शामिल होगी (और आप कुछ कोड स्पष्टता/डिबगैबिलिटी खो सकते हैं) –

+0

+1 बहुत अच्छा जवाब। धन्यवाद। –

+3

समस्या हल करने के लिए यह एक बात है। यह दूसरा है एक सुरुचिपूर्ण समाधान (जिसका मतलब है "आंखों पर आसान") लिखना। मुझे नहीं लगता कि यह कोड अच्छा दिखता है या पर्याप्त पठनीय है। मैं डेल्फी से धीरे-धीरे अपनी पठनीयता को खोने के लिए नफरत करता हूं, अन्यथा मेरी पसंदीदा भाषा के रूप में सी # पर स्विच न करने का एक कम कारण होगा। – Sam

1

उपयोग प्रकार alorithms में से एक Wikipedia द्वारा प्रस्ताव करते हैं। स्वैप फ़ंक्शन को सरणी तत्वों के समान प्रकार के अस्थायी चर का उपयोग करके सरणी तत्वों को स्वैप करना चाहिए। एक स्थिर सॉर्ट का उपयोग करें यदि आप उसी क्रम में रहने के लिए उसी सॉर्टऑर्डर पूर्णांक मान वाली प्रविष्टियां चाहते हैं जो वे पहले स्थान पर रहते थे।

2

एक सरणी के साथ, मैं या तो quicksort या संभवतः heapsort, और सिर्फ तुलना TExample.SortOrder उपयोग करने के लिए बदलने के लिए, स्वैप हिस्सा अभी भी बस पर कार्रवाई करने के लिए जा रहा है का उपयोग करेंगे सरणी और स्वैप पॉइंटर्स। यदि सरणी बहुत बड़ी है तो यदि आप बहुत अधिक प्रविष्टि और हटाना चाहते हैं तो आप एक लिंक्ड सूची संरचना चाहते हैं।

सी आधारित दिनचर्या, वहाँ कई यहाँ http://www.yendor.com/programming/sort/

एक अन्य साइट है, लेकिन पास्कल स्रोत http://www.dcc.uchile.cl/~rbaeza/handbook/sort_a.html

4

है अपनी जरूरत स्ट्रिंग के अनुसार क्रमबद्ध तो उपयोग अनुसार क्रमबद्ध TStringList और TString.AddObject(string, Pointer(int_val)) द्वारा रिकॉर्ड जोड़ने।

लेकिन अगर पूर्णांक फ़ील्ड और स्ट्रिंग द्वारा क्रमबद्ध की आवश्यकता है - TObjectList का उपयोग करें और सभी रिकॉर्ड जोड़ने के बाद पैरामीटर के रूप में आवश्यक क्रमबद्ध कार्यों के साथ TObjectList.Sort पर कॉल करें।

1

TStringList कुशल सॉर्ट विधि है।
यदि आप चाहते हैं तो TStringList ऑब्जेक्ट का उपयोग Sorted संपत्ति के साथ सही करें।

नोट: अधिक गति के लिए, क्रमबद्ध TStringList में ऑब्जेक्ट्स जोड़ें और अंत में संपत्ति को सही में बदलें।
नोट: पूर्णांक फ़ील्ड द्वारा क्रमबद्ध करने के लिए, स्ट्रिंग में कनवर्ट करें।
नोट: यदि डुप्लिकेट मान हैं, तो यह विधि मान्य नहीं है।

सम्मान।

2

यह सब आपके द्वारा क्रमबद्ध रिकॉर्ड की संख्या पर निर्भर करता है। यदि आप केवल कुछ सौ से भी कम क्रमबद्ध कर रहे हैं तो अन्य प्रकार के तरीके ठीक काम करते हैं, यदि आप अधिक सॉर्ट करने जा रहे हैं, तो पुरानी भरोसेमंद टर्बो पावर SysTools प्रोजेक्ट पर एक अच्छा नज़र डालें। स्रोत में एक बहुत अच्छा प्रकार एल्गोरिदम शामिल है। एक जो एक बहुत अच्छी नौकरी करता है जो लाखों रिकॉर्ड कुशल तरीके से छंटनी करता है।

यदि आप रिकॉर्ड्स की सूची को क्रमबद्ध करने के tStringList विधि का उपयोग करने जा रहे हैं, तो सुनिश्चित करें कि सूची में डालने से पहले आपका पूर्णांक दाईं ओर गद्देदार है। आप प्रारूप ('%। 10d', [rec।सॉर्टऑर्डर]) उदाहरण के लिए 10 अंकों के दाएं संरेखित करने के लिए।

12

(मैं जानता हूँ कि यह एक साल बाद है, लेकिन अभी भी उपयोगी सामग्री।)

पैड पूर्णांक मूल्यों को Skamradt के सुझाव मान लिया गया है कि आप एक स्ट्रिंग की तुलना का उपयोग कर सॉर्ट करने के लिए जा रहे हैं। यह धीमा होगा। प्रत्येक डालने के लिए कॉलिंग प्रारूप(), धीमा अभी भी। इसके बजाय, आप एक पूर्णांक तुलना करना चाहते हैं।

आप एक रिकॉर्ड प्रकार से शुरू करें:

TExample = record 
    SortOrder : integer; 
    SomethingElse : string; 
end; 

आप राज्य नहीं था कैसे रिकॉर्ड संग्रहीत किया गया है, या आप उन्हें कैसे उपयोग करने के लिए करना चाहता था एक बार हल कर। तो चलो आप उन्हें एक गतिशील सरणी में डाल मान लें:

var MyDA Array of TExample; 
... 
    SetLength(MyDA,NewSize);   //allocate memory for the dynamic array 
    for i:=0 to NewSize-1 do begin  //fill the array with records 
    MyDA[i].SortOrder := SomeInteger; 
    MyDA[i].SomethingElse := SomeString; 
    end; 

अब आप पूर्णांक मान SortOrder द्वारा इस सरणी क्रमबद्ध करना चाहते हैं। यदि आप जो चाहते हैं वह एक TStringList है (इसलिए आप ts.find विधि का उपयोग कर सकते हैं) तो आपको प्रत्येक स्ट्रिंग को सूची में जोड़ना चाहिए और सॉर्टऑर्डर को पॉइंटर के रूप में जोड़ना चाहिए। एक TObject सूचक है, जो TStringList.Object संपत्ति में संग्रहीत किया जाता में पूर्णांक SortOrder कास्टिंग की चाल

var tsExamples: TStringList;   //declare it somewhere (global or local) 
... 
    tsExamples := tStringList.create; //allocate it somewhere (and free it later!) 
... 
    tsExamples.Clear;     //now let's use it 
    tsExamples.sorted := False;   //don't want to sort after every add 
    tsExamples.Capacity := High(MyDA)+1 //don't want to increase size with every add 
             //an empty dynamic array has High() = -1 
    for i:=0 to High(MyDA) do begin 
    tsExamples.AddObject(MyDA[i].SomethingElse,TObject(MyDA[i].SortOrder)); 
    end; 

नोट: फिर सूचक क्रमित करें। (। इस तथ्य यह है कि पूर्णांक और सूचक एक ही आकार के होते हैं पर निर्भर करता है) कहीं न कहीं हम TObject संकेत तुलना करने के लिए एक समारोह को परिभाषित करना होगा: अब

function CompareObjects(ts:tStringList; Item1,Item2: integer): Integer; 
var i,j: integer; 
begin 
    Result := integer(ts.Objects[i]) - integer(ts.Objects[j]; 
end; 

, हम बजाय .CustomSort फोन करके .Object पर tsList सॉर्ट कर सकते हैं .Sort की (स्ट्रिंग मान पर सॉर्ट जो जाएगा।)

tsExample.CustomSort(@CompareObjects);  //Sort the list 
TStringList

अब क्रमबद्ध हो जाता है, तो आप .Count -1 0 से इस पर पुनरावृति और क्रमबद्ध क्रम में तार पढ़ सकते हैं।

लेकिन मान लीजिए कि आप एक TStringList नहीं चाहते थे, क्रमबद्ध क्रम में केवल एक सरणी। या रिकॉर्ड में इस उदाहरण में केवल एक स्ट्रिंग की तुलना में अधिक डेटा होता है, और आपका सॉर्ट ऑर्डर अधिक जटिल होता है। आप प्रत्येक स्ट्रिंग को जोड़ने का चरण छोड़ सकते हैं, और केवल एक टीएलिस्ट में आइटम के रूप में सरणी अनुक्रमणिका जोड़ सकते हैं। उसी तरह से ऊपर सब कुछ करते हैं, TStringList के बजाय एक TList का उपयोग को छोड़कर:

for i:=0 to Mlist.Count-1 do begin 
    Something := MyDA[integer(Mlist[i])].SomeField; 
    end; 

के रूप में: क्रमबद्ध क्रम में सरणी का उपयोग करने की

var Mlist: TList;     //a list of Pointers 
... 
    for i:=0 to High(MyDA) do 
    Mlist.add(Pointer(i));  //cast the array index as a Pointer 
    Mlist.Sort(@CompareRecords); //using the compare function below 

function CompareRecords(Item1, Item2: Integer): Integer; 
var i,j: integer; 
begin 
    i := integer(item1);   //recover the index into MyDA 
    j := integer(item2);   // and use it to access any field 
    Result := SomeFunctionOf(MyDA[i].SomeField) - SomeFunctionOf(MyDA[j].SomeField); 
end; 

अब जब कि Mlist क्रमबद्ध हो जाता है, यह एक लुकअप तालिका के रूप में उपयोग मैं टीएलआईस्ट पर पुनरावृत्ति करता हूं, हम क्रमबद्ध क्रम में सरणी अनुक्रमणिका वापस प्राप्त करते हैं। हमें उन्हें पूर्णांक में वापस लाने की जरूरत है, क्योंकि टीएलिस्ट सोचता है कि वे पॉइंटर्स हैं।

मुझे यह तरीका पसंद है, लेकिन आप टीएलआईटी में सरणी तत्वों को वास्तविक सूचकांक भी डाल सकते हैं, इसके सूचकांक के बजाय सरणी तत्व का पता जोड़कर। फिर उनका उपयोग करने के लिए आप उन्हें TExample रिकॉर्ड्स के पॉइंटर्स के रूप में डालेंगे। बैरी केली और कूलमैजिक ने अपने उत्तरों में ऐसा करने के लिए कहा।

+1

ऐसा लगता है कि यह सिर्फ एक दिन बाद है :) –

2

फास्ट सॉर्टिंग की आवश्यकता होने पर क्विकॉर्ट एल्गोरिदम का अक्सर उपयोग किया जाता है। डेल्फी उदाहरण के लिए List.Sort के लिए इसका उपयोग कर रहा है (या था)। डेल्फी सूची का उपयोग कुछ भी क्रमबद्ध करने के लिए किया जा सकता है, लेकिन यह एक हेवीवेट कंटेनर है, जो संरचनाओं पर पॉइंटर्स की एक सरणी जैसा दिखता है। यह हेवीवेट है भले ही हम इस धागे में गाय गॉर्डन जैसे चाल का उपयोग करें (इंडेक्स या पॉइंटर्स के स्थान पर कुछ भी डालें, या 32 बिट्स से छोटे होने पर सीधे मूल्य डालें): हमें एक सूची बनाने की आवश्यकता है ...

नतीजतन, संरचना के सरणी को आसानी से और तेजी से क्रमबद्ध करने का विकल्प msvcrt.dll से qsort C runtime function का उपयोग करना हो सकता है।

यहां एक घोषणा है जो अच्छी हो सकती है (चेतावनी: कोड केवल विंडोज़ पर पोर्टेबल)।

type TComparatorFunction = function(lpItem1: Pointer; lpItem2: Pointer): Integer; cdecl; 
procedure qsort(base: Pointer; num: Cardinal; size: Cardinal; lpComparatorFunction: TComparatorFunction) cdecl; external 'msvcrt.dll'; 

पूर्ण उदाहरण here

नोटिस कि रिकॉर्ड्स बड़े होने पर रिकॉर्ड की सरणी को सीधे सॉर्ट करना धीमा हो सकता है। उस स्थिति में, रिकॉर्ड में पॉइंटर की एक सरणी को क्रमबद्ध करना तेज हो सकता है (किसी भी तरह सूची सूची की तरह)।

0

मैंने एक बहुत ही सरल उदाहरण बनाया है जो सॉर्ट फ़ील्ड स्ट्रिंग है तो सही तरीके से काम करता है।

Type 
    THuman = Class 
    Public 
    Name: String; 
    Age: Byte; 
    Constructor Create(Name: String; Age: Integer); 
    End; 

Constructor THuman.Create(Name: String; Age: Integer); 
Begin 
    Self.Name:= Name; 
    Self.Age:= Age; 
End; 

Procedure Test(); 
Var 
Human: THuman; 
Humans: Array Of THuman; 
List: TStringList; 
Begin 

SetLength(Humans, 3); 
Humans[0]:= THuman.Create('David', 41); 
Humans[1]:= THuman.Create('Brian', 50); 
Humans[2]:= THuman.Create('Alex', 20); 

List:= TStringList.Create; 
List.AddObject(Humans[0].Name, TObject(Humans[0])); 
List.AddObject(Humans[1].Name, TObject(Humans[1])); 
List.AddObject(Humans[2].Name, TObject(Humans[2])); 
List.Sort; 

Human:= THuman(List.Objects[0]); 
Showmessage('The first person on the list is the human ' + Human.name + '!'); 

List.Free; 
End; 
0

आप डेल्फी XE2 या नए है, तो आप की कोशिश कर सकते हैं:

var 
    someVar: array of TExample; 
    list: TList<TExample>; 
    sortedVar: array of TExample; 
begin 
    list := TList<TExample>.Create(someVar); 
    try 
    list.Sort; 
    sortedVar := list.ToArray; 
    finally 
    list.Free; 
    end; 
end; 
संबंधित मुद्दे