सी # सॉर्टेबल संग्रह जो डुप्लिकेट कुंजियों की अनुमति देता है


95

मैं अनुक्रम लिखने के लिए एक कार्यक्रम लिख रहा हूं जिसमें विभिन्न वस्तुएं रिपोर्ट में दिखाई देंगी। अनुक्रम एक्सेल स्प्रेडशीट पर Y स्थिति (सेल) है।

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

SortedList list = new SortedList();

Header h = new Header();
h.XPos = 1;
h.name = "Header_1";
list.Add(h.XPos, h);

h = new Header();
h.XPos = 1;
h.name = "Header_2";
list.Add(h.XPos, h);

मुझे पता है कि SortedListयह अनुमति नहीं देगा और मैं वैकल्पिक खोज रहा हूं। मैं डुप्लिकेट को खत्म नहीं करना चाहता और पहले से ही कोशिश कर रहा हूं List<KeyValuePair<int, object>>

धन्यवाद।


1
क्या सदस्यों की प्रारंभिक सूची दिए जाने के बाद संग्रह को आवेषण / निष्कासन का समर्थन करने की आवश्यकता है ?
ऐनी

2
जब आपने प्रयास किया तो क्या काम नहीं आया List?
diceguyd30

मैं सिर्फ छँटाई नहीं चाहता और वस्तु प्राप्त करता हूँ। लेकिन इसके बजाय मैं पूरी तरह से सूचीबद्ध सूची प्राप्त करना चाहता हूं। इसलिए नीचे दिए गए उदाहरण में, हेडर ऑब्जेक्ट दोनों मौजूद होना चाहिए और क्रम में एक दूसरे के नीचे होना चाहिए। अगर मैं XPos = 2 के साथ एक और हेडर ऑब्जेक्ट जोड़ता हूं, तो मुझे सूची में 3 ऑब्जेक्ट्स,
XPos के

बस एक नोट: जब मैं इस प्रकार की स्थिति का सामना करता हूं, तो मुझे पता चलता है कि जिन वस्तुओं को काम नहीं मिला है, उनके लिए अल्पज्ञात बाइनरीसर्च व्यवहार के संयोजन में सामान्य सूची ।
जे ट्राना

जवाबों:


76

अपने खुद के IComparer का उपयोग करें!

जैसे पहले से ही कुछ अन्य उत्तरों में कहा गया है, आपको अपने स्वयं के तुलना वर्ग का उपयोग करना चाहिए। इस खातिर मैं एक सामान्य IComparer वर्ग का उपयोग करता हूं, जो कि कुछ भी काम करता है जो IComparable लागू करता है:

/// <summary>
/// Comparer for comparing two keys, handling equality as beeing greater
/// Use this Comparer e.g. with SortedLists or SortedDictionaries, that don't allow duplicate keys
/// </summary>
/// <typeparam name="TKey"></typeparam>
public class DuplicateKeyComparer<TKey>
                :
             IComparer<TKey> where TKey : IComparable
{
    #region IComparer<TKey> Members

    public int Compare(TKey x, TKey y)
    {
        int result = x.CompareTo(y);

        if (result == 0)
            return 1;   // Handle equality as beeing greater
        else
            return result;
    }

    #endregion
}

जब आप एक नया SortedList, SortedDictionary आदि को प्रेरित करते हुए इसका उपयोग करेंगे:

SortedList<int, MyValueClass> slist = new SortedList<int, MyValueClass>(new DuplicateKeyComparer<int>());

यहाँ int कुंजी है जो डुप्लिकेट हो सकती है।


40
लेकिन आप इससे कोई भी कुंजी नहीं निकाल पाएंगे।
शास्वत

11
हाँ, सही है, शववत! आप निकालें (कुंजी) या IndexOfKey (कुंजी) का उपयोग नहीं कर सकते, क्योंकि तुलना करने वाला कभी भी महत्वपूर्ण समानता को इंगित करने के लिए 0 नहीं लौटाता है। यदि आप उनके सूचकांक हैं, तो आप आइटम हटाने के लिए RemoveAt (सूचकांक) कर सकते हैं।
क्लेस्टरबैक्स

1
मुझे भी उसी समस्या का सामना करना पड़ा, मैंने इस्तेमाल किया SortedDictionary। यह भी हटाने की अनुमति देता है।
शशवत

10
ध्यान दें कि आप तोड़ रहे हैं रिफ्लेक्सिविटी अपने comparer इस तरह के। यह BCL में चीजों को तोड़ सकता है (और करेगा)।
घोड़

1
यह वास्तव में आदेश रखने के लिए -1 लौटना चाहिए
एम। काज़म अखगीरी

16

आप सुरक्षित रूप से सूची का उपयोग कर सकते हैं <>। सूची में एक क्रमबद्ध विधि है, एक अधिभार जिसमें से IComparer स्वीकार करता है। आप अपना स्वयं का सॉर्टर वर्ग बना सकते हैं। यहाँ एक उदाहरण है:

private List<Curve> Curves;
this.Curves.Sort(new CurveSorter());

public class CurveSorter : IComparer<Curve>
{
    public int Compare(Curve c1, Curve c2)
    {
        return c2.CreationTime.CompareTo(c1.CreationTime);
    }
}

1
मैं सिर्फ छँटाई नहीं चाहता और वस्तु प्राप्त करता हूँ। लेकिन इसके बजाय मैं पूरी तरह से सूचीबद्ध सूची प्राप्त करना चाहता हूं। इसलिए नीचे दिए गए उदाहरण में, हेडर ऑब्जेक्ट दोनों मौजूद होना चाहिए और क्रम में एक दूसरे के नीचे होना चाहिए। यदि मैं XPos = 2 के साथ एक और हैडर ऑब्जेक्ट जोड़ता हूं, तो मुझे सूची में 3 ऑब्जेक्ट होना चाहिए, 2 ऑब्जेक्ट्स में XPos = 1 और तीसरे के साथ
XPos

1
कहने का मतलब यह है कि सूची में किसी तत्व को डाले जाने के बाद उसे सही स्थिति में डाला जाना चाहिए। कृपया मुझे सही करें अगर गलत। मुझे एक बार देखने दो, कुछ ही पल में वापस मिल जाएगा
दीप्ति मेहता

ध्यान दें कि सूची <T> .Sort संग्रह आकार के आधार पर कई सॉर्टिंग एल्गोरिदम का उपयोग करता है और उनमें से सभी स्थिर प्रकार नहीं हैं। तो वस्तुओं को उस संग्रह में जोड़ा गया जो समकक्ष की तुलना में वे जिस क्रम में जोड़े गए थे, उसमें प्रकट नहीं हो सकते हैं।
मौन स्वर

मैं इस विकल्प के साथ गया था, इसलिए मैं एक शब्दकोश में कार्यों को कम करने के साथ KeyValuePairs की अपर्याप्त मात्रा बनाना बंद कर सकता
हूं

10

मैं निम्नलिखित का उपयोग करता हूं:

public class TupleList<T1, T2> : List<Tuple<T1, T2>> where T1 : IComparable
{
    public void Add(T1 item, T2 item2)
    {
        Add(new Tuple<T1, T2>(item, item2));
    }

    public new void Sort()
    {
        Comparison<Tuple<T1, T2>> c = (a, b) => a.Item1.CompareTo(b.Item1);
        base.Sort(c);
    }

}

मेरा परीक्षण मामला:

[TestMethod()]
    public void SortTest()
    {
        TupleList<int, string> list = new TupleList<int, string>();
        list.Add(1, "cat");
        list.Add(1, "car");
        list.Add(2, "dog");
        list.Add(2, "door");
        list.Add(3, "elephant");
        list.Add(1, "coconut");
        list.Add(1, "cab");
        list.Sort();
        foreach(Tuple<int, string> tuple in list)
        {
            Console.WriteLine(string.Format("{0}:{1}", tuple.Item1,tuple.Item2));
        }
        int expected_first = 1;
        int expected_last = 3;
        int first = list.First().Item1;  //requires using System.Linq
        int last = list.Last().Item1;    //requires using System.Linq
        Assert.AreEqual(expected_first, first);
        Assert.AreEqual(expected_last, last);
    }

उत्पादन:

1:cab
1:coconut
1:car
1:cat
2:door
2:dog
3:elephant

टपल नेट के सभी संस्करणों में उपलब्ध नहीं है, लेकिन KeyValuePair <कश्मीर, वी> साथ substitued किया जा सकता है
रूबेन

6

समस्या यह है कि डेटा संरचना डिज़ाइन आवश्यकताओं से मेल नहीं खाती है: एक ही XPos के लिए कई हेडर स्टोर करना आवश्यक है। इसलिए, का SortedList<XPos, value>मान नहीं होना चाहिए Header, लेकिन का मूल्य होना चाहिए List<Header>। यह एक सरल और छोटा बदलाव है, लेकिन यह सभी समस्याओं को हल करता है और अन्य सुझाए गए समाधानों की तरह नई समस्याएं पैदा करने से बचता है (नीचे स्पष्टीकरण देखें):

using System;
using System.Collections.Generic;

namespace TrySortedList {
  class Program {

    class Header {
      public int XPos;
      public string Name;
    }

    static void Main(string[] args) {
      SortedList<int, List<Header>> sortedHeaders = new SortedList<int,List<Header>>();
      add(sortedHeaders, 1, "Header_1");
      add(sortedHeaders, 1, "Header_2");
      add(sortedHeaders, 2, "Header_3");
      foreach (var headersKvp in sortedHeaders) {
        foreach (Header header in headersKvp.Value) {
          Console.WriteLine(header.XPos + ": " + header.Name);
        }
      }
    }

    private static void add(SortedList<int, List<Header>> sortedHeaders, int xPos, string name) {
      List<Header> headers;
      if (!sortedHeaders.TryGetValue(xPos, out headers)){
        headers = new List<Header>();
        sortedHeaders[xPos] = headers;
      }
      headers.Add(new Header { XPos = xPos, Name = name });
    }
  }
}

Output:
1: Header_1
1: Header_2
2: Header_3

कृपया ध्यान दें कि एक "मज़ेदार" कुंजी जोड़ना, जैसे कि एक यादृच्छिक संख्या जोड़ना या एक ही मूल्य के साथ 2 XPos का नाटक करना कई अन्य समस्याओं के लिए भिन्न होता है। उदाहरण के लिए किसी विशेष हैडर को हटाना मुश्किल या असंभव हो जाता है।

यह भी ध्यान दें कि छंटनी का प्रदर्शन बहुत बेहतर है यदि केवल कुछ List<Header>को हर से हल करना है Header। उदाहरण: यदि 100 XPos हैं और प्रत्येक में 100 हेडर हैं, तो 10000 Headerको 100 के विपरीत हल करने की आवश्यकता हैList<Header>

बेशक, इस समाधान का एक नुकसान भी है: यदि केवल 1 हेडर के साथ कई एक्सपीओएस हैं, क्योंकि कई सूचियों को बनाने की आवश्यकता है, जो कुछ ओवरहेड है।


यह सबसे सीधा उपाय है। इसके अलावा सॉर्टेड वर्क की जांच करें, यह समान है, कुछ मामलों में तेज है।
होगन

यह वास्तव में एक अच्छा उपाय है। कोई उस कार्यक्षमता को कुछ कस्टम संग्रह ऑब्जेक्ट में आसानी से लपेट सकता है और यह काफी उपयोगी होगा। अच्छा सोचा, पीटर साझा करने के लिए धन्यवाद!
एडम पी।

5

सबसे सरल समाधान (उपरोक्त सभी की तुलना में): उपयोग करें SortedSet<T>, यह एक IComparer<SortableKey>वर्ग को स्वीकार करता है , फिर तुलना विधि को इस तरह लागू करें:

public int Compare(SomeClass x, SomeClass y)
{
    var compared = x.SomeSortableKeyTypeField.CompareTo(y.SomeSortableKeyTypeField);
    if (compared != 0)
        return compared;

    // to allow duplicates
    var hashCodeCompare = x.GetHashCode().CompareTo(y.GetHashCode());
    if (hashCodeCompare != 0)
        return hashCodeCompare;

    if (Object.ReferenceEquals(x, y))
        return 0;

    // for weird duplicate hashcode cases, throw as below or implement your last chance comparer
    throw new ComparisonFailureException();

}

4
मैंने SortedSet का उपयोग किया है <T> और T की स्वयं की इंक्रीमेंटल आईडी थी जो कि प्रत्येक T को इंश्योर करने के लिए प्रत्येक तात्कालिकता पर बढ़ा हुआ है, अन्य फ़ील्ड के साथ भी समान है।
स्किचन

3
तुलना के लिए GetHashCode खतरनाक है। अनपेक्षित गलत डुप्लिकेट हो सकता है। यह ज्यादातर समय काम कर सकता है, लेकिन मैं इसका इस्तेमाल कभी भी गंभीर नहीं करूंगा।
होगन

4

आपकी सहायता के लिए धन्यवाद। अधिक खोज करते हुए, मुझे यह समाधान मिला। (अन्य प्रश्न में Stackoverflow.com में उपलब्ध)

सबसे पहले, मैंने एक वर्ग बनाया जो कक्षाओं के लिए मेरी वस्तुओं को अलग करेगा (हेडर, फुटर आदि)

public class MyPosition
{
    public int Position { get; set; }
    public object MyObjects{ get; set; }
}

तो यह वर्ग वस्तुओं पर पकड़ रखने वाला है, और प्रत्येक वस्तु का पॉसएक्स इंट पोज़िशन के रूप में जाता है

List<MyPosition> Sequence= new List<MyPosition>();
Sequence.Add(new MyPosition() { Position = 1, Headerobject });
Sequence.Add(new MyPosition() { Position = 2, Headerobject1 });
Sequence.Add(new MyPosition() { Position = 1, Footer });

League.Sort((PosA, PosB) => PosA.Position.CompareTo(PosB.Position));

अंततः मुझे जो मिलता है वह "अनुक्रम" की क्रमबद्ध सूची है।


2

क्या आपने कोशिश की है Lookup<TKey, TElement>कि डुप्लिकेट कुंजियों की अनुमति होगी http://msdn.microsoft.com/en-us/library/bb460184.aspx


धन्यवाद। मेरी समस्या यह है कि वस्तुएं केवल एक प्रकार की नहीं होंगी (सिर्फ हेडर नहीं), वे अलग-अलग हो सकती हैं (पाद, साइडबार इत्यादि कह सकते हैं) लेकिन प्रत्येक में
XPos होंगे

इसके अलावा, Lookupमेरा मानना ​​है कि कोई भी सार्वजनिक निर्माणकर्ता नहीं है। इसके आसपास कोई अच्छा तरीका?
जेफ बी

1
@JeffBridgman आपको Linq पर निर्भर रहना होगा। आप ToLookupकिसी पर भी कर सकते हैं IEnumerable<T>
नवाफाल

8
हाँ, यह डुप्लिकेट कुंजियों की अनुमति देता है, लेकिन यह कुछ भी क्रमबद्ध नहीं रखता है!
रोमन स्टार्कोव

2

आप SortedList का उपयोग कर सकते हैं, TKey के लिए अपने मूल्य का उपयोग कर सकते हैं और TValue के लिए int (काउंट) कर सकते हैं।

यहाँ एक नमूना है: एक फ़ंक्शन जो किसी शब्द के अक्षरों को क्रमबद्ध करता है।

    private string sortLetters(string word)
    {
        var input = new System.Collections.Generic.SortedList<char, int>();

        foreach (var c in word.ToCharArray())
        {
            if (input.ContainsKey(c))
                input[c]++;
            else
                input.Add(c, 1);
        }

        var output = new StringBuilder();

        foreach (var kvp in input)
        {
            output.Append(kvp.Key, kvp.Value);
        }

        string s;

        return output.ToString();

    }

2

यह संग्रह वर्ग डुप्लिकेट बनाए रखेगा और डुप्लिकेट के लिए सॉर्ट क्रम सम्मिलित करेगा। एक अद्वितीय मूल्य के साथ आइटम को टैग करने के लिए चाल है, क्योंकि वे एक स्थिर क्रम को बनाए रखने के लिए डाले गए हैं। फिर हम इसे एक ICollection इंटरफ़ेस में लपेटते हैं।

public class SuperSortedSet<TValue> : ICollection<TValue>
{
    private readonly SortedSet<Indexed<TValue>> _Container;
    private int _Index = 0;
    private IComparer<TValue> _Comparer;

    public SuperSortedSet(IComparer<TValue> comparer)
    {
        _Comparer = comparer;
        var c2 = new System.Linq.Comparer<Indexed<TValue>>((p0, p1) =>
        {
            var r = _Comparer.Compare(p0.Value, p1.Value);
            if (r == 0)
            {
                if (p0.Index == -1
                    || p1.Index == -1)
                    return 0;

                return p0.Index.CompareTo(p1.Index);

            }
            else return r;
        });
        _Container = new SortedSet<Indexed<TValue>>(c2);
    } 

    public IEnumerator<TValue> GetEnumerator() { return _Container.Select(p => p.Value).GetEnumerator(); }

    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

    public void Add(TValue item) { _Container.Add(Indexed.Create(_Index++, item)); }

    public void Clear() { _Container.Clear();}

    public bool Contains(TValue item) { return _Container.Contains(Indexed.Create(-1,item)); }

    public void CopyTo(TValue[] array, int arrayIndex)
    {
        foreach (var value in this)
        {
            if (arrayIndex >= array.Length)
            {
                throw new ArgumentException("Not enough space in array");
            }
            array[arrayIndex] = value;
            arrayIndex++;
        }
    }

    public bool Remove(TValue item) { return _Container.Remove(Indexed.Create(-1, item)); }

    public int Count {
        get { return _Container.Count; }
    }
    public bool IsReadOnly {
        get { return false; }
    }
}

एक परीक्षण वर्ग

[Fact]
public void ShouldWorkWithSuperSortedSet()
{
    // Sort points according to X
    var set = new SuperSortedSet<Point2D>
        (new System.Linq.Comparer<Point2D>((p0, p1) => p0.X.CompareTo(p1.X)));

    set.Add(new Point2D(9,10));
    set.Add(new Point2D(1,25));
    set.Add(new Point2D(11,-10));
    set.Add(new Point2D(2,99));
    set.Add(new Point2D(5,55));
    set.Add(new Point2D(5,23));
    set.Add(new Point2D(11,11));
    set.Add(new Point2D(21,12));
    set.Add(new Point2D(-1,76));
    set.Add(new Point2D(16,21));

    var xs = set.Select(p=>p.X).ToList();
    xs.Should().BeInAscendingOrder();
    xs.Count.Should()
       .Be(10);
    xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,5,9,11,11,16,21});

    set.Remove(new Point2D(5,55));
    xs = set.Select(p=>p.X).ToList();
    xs.Count.Should()
       .Be(9);
    xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,9,11,11,16,21});

    set.Remove(new Point2D(5,23));
    xs = set.Select(p=>p.X).ToList();
    xs.Count.Should()
       .Be(8);
    xs.ShouldBeEquivalentTo(new[]{-1,1,2,9,11,11,16,21});

    set.Contains(new Point2D(11, 11))
       .Should()
       .BeTrue();

    set.Contains(new Point2D(-1, 76))
        .Should().BeTrue();

    // Note that the custom compartor function ignores the Y value
    set.Contains(new Point2D(-1, 66))
        .Should().BeTrue();

    set.Contains(new Point2D(27, 66))
        .Should().BeFalse();

}

टैगिंग संरचना

public struct Indexed<T>
{
    public int Index { get; private set; }
    public T Value { get; private set; }
    public Indexed(int index, T value) : this()
    {
        Index = index;
        Value = value;
    }

    public override string ToString()
    {
        return "(Indexed: " + Index + ", " + Value.ToString () + " )";
    }
}

public class Indexed
{
    public static Indexed<T> Create<T>(int indexed, T value)
    {
        return new Indexed<T>(indexed, value);
    }
}

लैम्ब्डा तुलनित्र सहायक

public class Comparer<T> : IComparer<T>
{
    private readonly Func<T, T, int> _comparer;

    public Comparer(Func<T, T, int> comparer)
    {
        if (comparer == null)
            throw new ArgumentNullException("comparer");
        _comparer = comparer;
    }

    public int Compare(T x, T y)
    {
        return _comparer(x, y);
    }
}

1

समस्या यह है कि आप कुछ का उपयोग कुंजी के रूप में करते हैं जो कुंजी नहीं है (क्योंकि यह कई बार होता है)।

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

या आप वह स्थान बनाते हैं List<List<Header>>जहाँ आपका पहला सूची सूचकांक x-स्थिति और आंतरिक सूची सूचकांक y-स्थिति को परिभाषित करता है (या यदि आप इसके विपरीत)।


एक कुंजी के कई उदाहरण हो सकते हैं जब तक कि यह एक प्राथमिक कुंजी नहीं है। कम से कम यही है कि उन्होंने मुझे उस डेटाबेस वर्ग में बताया जो मैंने लिया था।
आमलोग १

1
यह उत्तर थोड़ा छोटा है, लेकिन यह समस्या को ठीक से समझाता है और सही समाधान प्रदान करता है, अर्थात SortedList <int, List <Heath >> का उपयोग करके। यह हेडर को क्रमबद्ध रखता है और एक ही xPos पर कई हेडर स्टोर कर सकता है। कोड नमूने के लिए मेरे उत्तर के लिए देखें। मैंने इसका उत्तर दिया, क्योंकि यह सही दिशा में इशारा करता है। कृपया 1 जवाब मेरे उत्तर भी अगर आपको लगता है कि यह मददगार है।
पीटर ह्यूबर

1

इसके लिए मुख्य (दंड का उद्देश्य) एक- IComparableआधारित वर्ग बनाना है जो समानता और हैशिंग को बनाए रखता है, लेकिन कभी भी 0 की तुलना नहीं करता है यदि समान है। यह किया जा सकता है, और एक युगल बोनस के साथ बनाया जा सकता है - स्थिर सॉर्टिंग (अर्थात, सॉर्ट की गई सूची में जोड़े गए मान पहले उनकी स्थिति बनाए रखेंगे), और ToString()बस वास्तविक कुंजी स्ट्रिंग मान वापस कर सकते हैं।

यहाँ एक महत्वपूर्ण कुंजी है जो चाल करना चाहिए:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace System
{
    /// <summary>
    /// Defined in Totlsoft.Util.
    /// A key that will always be unique but compares
    /// primarily on the Key property, which is not required
    /// to be unique.
    /// </summary>
    public struct StableKey : IComparable<StableKey>, IComparable
    {
        private static long s_Next;
        private long m_Sequence;
        private IComparable m_Key;

        /// <summary>
        /// Defined in Totlsoft.Util.
        /// Constructs a StableKey with the given IComparable key.
        /// </summary>
        /// <param name="key"></param>
        public StableKey( IComparable key )
        {
            if( null == key )
                throw new ArgumentNullException( "key" );

            m_Sequence = Interlocked.Increment( ref s_Next );
            m_Key = key;
        }

        /// <summary>
        /// Overridden. True only if internal sequence and the
        /// Key are equal.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals( object obj )
        {
            if( !( obj is StableKey ) )
                return false;

            var dk = (StableKey)obj;

            return m_Sequence.Equals( dk.m_Sequence ) &&
                Key.Equals( dk.Key );
        }

        /// <summary>
        /// Overridden. Gets the hash code of the internal
        /// sequence and the Key.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return m_Sequence.GetHashCode() ^ Key.GetHashCode();
        }

        /// <summary>
        /// Overridden. Returns Key.ToString().
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Key.ToString();
        }

        /// <summary>
        /// The key that will be compared on.
        /// </summary>
        public IComparable Key
        {
            get
            {
                if( null == m_Key )
                    return 0;

                return m_Key;
            }
        }

        #region IComparable<StableKey> Members

        /// <summary>
        /// Compares this Key property to another. If they
        /// are the same, compares the incremented value.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo( StableKey other )
        {
            var cmp = Key.CompareTo( other.Key );
            if( cmp == 0 )
                cmp = m_Sequence.CompareTo( other.m_Sequence );

            return cmp;
        }

        #endregion

        #region IComparable Members

        int IComparable.CompareTo( object obj )
        {
            return CompareTo( (StableKey)obj );
        }

        #endregion
    }
}

यह एक अच्छा विचार है। मैंने अवधारणा को एक कस्टम ICollection में लपेट दिया। देखें stackoverflow.com/a/21625939/158285
bradgonesurfing

0

Linq.Lookup शांत और सभी है, लेकिन अगर आपका लक्ष्य केवल "कुंजियों" पर लूप करना है, जबकि उन्हें डुप्लिकेट करने की अनुमति है तो आप इस संरचना का उपयोग कर सकते हैं:

List<KeyValuePair<String, String>> FieldPatterns = new List<KeyValuePair<string, string>>() {
   new KeyValuePair<String,String>("Address","CommonString"),
   new KeyValuePair<String,String>("Username","UsernamePattern"),
   new KeyValuePair<String,String>("Username","CommonString"),
};

तो आप लिख सकते हैं:

foreach (KeyValuePair<String,String> item in FieldPatterns)
{
   //use item.Key and item.Value
}

HTH


0

चाल एक अद्वितीय कुंजी के साथ अपनी वस्तु को बढ़ाने के लिए है। निम्नलिखित परीक्षा देखें जो उत्तीर्ण होती है। मैं अपने अंकों को उनके एक्स मान द्वारा क्रमबद्ध रखना चाहता हूं। मेरे तुलनात्मक फ़ंक्शन में केवल एक नग्न प्वाइंट 2 डी का उपयोग करने से समान एक्स मूल्य के साथ अंक समाप्त हो जाएंगे। इसलिए मैं Index2 नामक एक टैगिंग क्लास में पॉइंट 2 डी लपेटता हूं।

[Fact]
public void ShouldBeAbleToUseCustomComparatorWithSortedSet()
{
    // Create comparer that compares on X value but when X
    // X values are uses the index
    var comparer = new 
        System.Linq.Comparer<Indexed<Point2D>>(( p0, p1 ) =>
        {
            var r = p0.Value.X.CompareTo(p1.Value.X);
            return r == 0 ? p0.Index.CompareTo(p1.Index) : r;
        });

    // Sort points according to X
    var set = new SortedSet<Indexed<Point2D>>(comparer);

    int i=0;

    // Create a helper function to wrap each point in a unique index
    Action<Point2D> index = p =>
    {
        var ip = Indexed.Create(i++, p);
        set.Add(ip);
    };

    index(new Point2D(9,10));
    index(new Point2D(1,25));
    index(new Point2D(11,-10));
    index(new Point2D(2,99));
    index(new Point2D(5,55));
    index(new Point2D(5,23));
    index(new Point2D(11,11));
    index(new Point2D(21,12));
    index(new Point2D(-1,76));
    index(new Point2D(16,21));
    set.Count.Should()
       .Be(10);
    var xs = set.Select(p=>p.Value.X).ToList();
    xs.Should()
      .BeInAscendingOrder();
    xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,5,9,11,11,16,21});

}

इस कार्य को करने के लिए उपयोगिताएँ हैं

एक तुलना करनेवाला जो लंबोदर लेता है

public class Comparer<T> : IComparer<T>
{
    private readonly Func<T, T, int> _comparer;

    public Comparer(Func<T, T, int> comparer)
    {
        if (comparer == null)
            throw new ArgumentNullException("comparer");
        _comparer = comparer;
    }

    public int Compare(T x, T y)
    {
        return _comparer(x, y);
    }
}

एक टैगिंग संरचना

public struct Indexed<T>
{
    public int Index { get; private set; }
    public T Value { get; private set; }
    public Indexed(int index, T value) : this()
    {
        Index = index;
        Value = value;
    }

    public override string ToString()
    {
        return "(Indexed: " + Index + ", " + Value.ToString () + " )";
    }
}

public class Indexed
{
    public static Indexed<T> Create<T>(int indexed, T value)
    {
        return new Indexed<T>(indexed, value);
    }
}

उपरोक्त अवधारणाओं के एक पूर्ण आवरण के लिए एक कस्टम ICollection वर्ग में मेरे अन्य उत्तर को देखें
bradgonesurfing

0

इस तरह मैंने समस्या का समाधान किया। यह थ्रेड-सुरक्षित होने के लिए है, हालांकि lockयदि आपको इसकी आवश्यकता नहीं है, तो आप केवल एस को हटा सकते हैं । Insertएक इंडेक्स पर मनमाना नोट भी समर्थित नहीं है क्योंकि यह सॉर्ट की स्थिति का उल्लंघन कर सकता है।

public class ConcurrentOrderedList<Titem, Tsort> : ICollection<Titem>
{
    private object _lock = new object();
    private SortedDictionary<Tsort, List<Titem>> _internalLists;
    Func<Titem, Tsort> _getSortValue;
    
    public ConcurrentOrderedList(Func<Titem,Tsort> getSortValue)
    {
        _getSortValue = getSortValue;
        _internalLists = new SortedDictionary<Tsort, List<Titem>>();            
    }

    public int Count { get; private set; }

    public bool IsReadOnly => false;

    public void Add(Titem item)
    {
        lock (_lock)
        {
            List<Titem> values;
            Tsort sortVal = _getSortValue(item);
            if (!_internalLists.TryGetValue(sortVal, out values))
            {
                values = new List<Titem>();
                _internalLists.Add(sortVal, values);
            }
            values.Add(item);
            Count++;
        }            
    }

    public bool Remove(Titem item)
    {
        lock (_lock)
        {
            List<Titem> values;
            Tsort sortVal = _getSortValue(item);
            if (!_internalLists.TryGetValue(sortVal, out values))
                return false;

            var removed = values.Remove(item);
            if (removed)
                Count--;
            return removed;
        }
    }

    public void Clear()
    {
        lock (_lock)
        {
            _internalLists.Clear();
        }
    }

    public bool Contains(Titem item)
    {
        lock (_lock)
        {
            List<Titem> values;
            Tsort sortVal = _getSortValue(item);
            if (!_internalLists.TryGetValue(sortVal, out values))
                return false;
            return values.Contains(item);
        }
    }

    public void CopyTo(Titem[] array, int arrayIndex)
    {
        int i = arrayIndex;
        lock (_lock)
        {
            foreach (var list in _internalLists.Values)
            {
                list.CopyTo(array, i);
                i += list.Count;
            }
        }
    }

    public IEnumerator<Titem> GetEnumerator()
    {
        foreach (var list in _internalLists.Values)
        {
            foreach (var item in list)
                yield return item;
        }
    }

    public int IndexOf(Titem item)
    {
        int i = 0;
        var sortVal = _getSortValue(item);
        lock (_lock)
        {               
            foreach (var list in _internalLists)
            {
                if (object.Equals(list.Key, sortVal))
                {
                    int intIndex = list.Value.IndexOf(item);
                    if (intIndex == -1)
                        return -1;
                    return i + intIndex;
                }
                i += list.Value.Count;
            }
            return -1;
        }           
    }

    public void Insert(int index, Titem item)
    {
        throw new NotSupportedException();
    }

    // Note this method is indeterminate if there are multiple
    // items in the same sort position!
    public void RemoveAt(int index)
    {
        int i = 0;
        lock (_lock)
        {
            foreach (var list in _internalLists.Values)
            {
                if (i + list.Count < index)
                {
                    i += list.Count;
                    continue;
                }
                else
                {
                    list.RemoveAt(index - i);
                    return;
                }
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

-1

एक वर्ग बनाएं और सूची को क्वेरी करें:

Public Class SortingAlgorithm
{
    public int ID {get; set;}
    public string name {get; set;}
    public string address1 {get; set;}
    public string city {get; set;}
    public string state {get; set;}
    public int age {get; set;}
}

//declare a sorting algorithm list
List<SortingAlgorithm> sortAlg = new List<SortingAlgorithm>();

//Add multiple values to the list
sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});
sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});
sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});

//query and order by the list
  var sortedlist = (from s in sortAlg
                    select new { s.ID, s.name, s.address1, s.city, s.state, s.age })
                                                     .OrderBy(r => r.ID)
                                                     .ThenBy(r=> r.name)
                                                     .ThenBy(r=> r.city)
                                                     .ThenBy(r=>r.state)
                                                     .ThenBy(r=>r.age);

-1

यहाँ मेरा इस पर ले रहा है। ज्ञात हो, यहां ड्रेगन हो सकते हैं, सी # अभी भी मेरे लिए काफी नया है।

  • डुप्लिकेट कुंजियों की अनुमति है, मान एक सूची में संग्रहीत किए जाते हैं
  • मैंने इसे एक क्रमबद्ध कतार के रूप में उपयोग किया, इसलिए नाम और विधियाँ

उपयोग:

SortedQueue<MyClass> queue = new SortedQueue<MyClass>();
// new list on key "0" is created and item added
queue.Enqueue(0, first);
// new list on key "1" is created and item added
queue.Enqueue(1, second);
// items is added into list on key "0"
queue.Enqueue(0, third);
// takes the first item from list with smallest key
MyClass myClass = queue.Dequeue();
class SortedQueue<T> {
  public int Count;
  public SortedList<int, List<T>> Queue;

  public SortedQueue() {
    Count = 0;
    Queue = new SortedList<int, List<T>>();
  }

  public void Enqueue(int key, T value) {
    List<T> values;
    if (!Queue.TryGetValue(key, out values)){
      values = new List<T>();
      Queue.Add(key, values);
      Count += 1;
    }
    values.Add(value);
  }

  public T Dequeue() {
    if (Queue.Count > 0) {
      List<T> smallest = Queue.Values[0];
      if (smallest.Count > 0) {
        T item = smallest[0];
        smallest.Remove(item);
        return item;
      } else {
        Queue.RemoveAt(0);
        Count -= 1;
        return Dequeue();
      }
    }
    return default(T);
  }
}

Queueबीसीएल में पहले से ही एक वर्ग है, जो वस्तुओं के पहले-इन, पहले-आउट संग्रह का प्रतिनिधित्व करता है। आपकी कक्षा के शब्दार्थ अलग हैं। आपकी कक्षा में एक शुरुआत है (जहां आइटम समाप्त हो गए हैं) लेकिन कोई अंत नहीं है (एक आइटम को कहीं भी डाला जा सकता है)। तो Enqueueअपनी कक्षा में विधि अर्थहीन IMHO है।
थियोडोर ज़ूलियास

@ TheodorZoulias Yup, नामकरण थोड़ा सा श * टी यहाँ है, लेकिन मुझे शायद ही लगता है कि यह एक चढ़ाव के हकदार हैं, इसमें ओपी की जरूरत है और यह केवल इनपुट / आउटपुट विधियों के नाम बदलने और फिर से लागू करने की बात है। ऐसा क्यों कहा जाता है? मुझे एक संरचना की आवश्यकता थी जिसे मैं थोड़ी देर के लूप में शुरू से खाली कर सकता हूं और प्राथमिकता मूल्य के आधार पर नए आइटम जोड़ सकता हूं। इसलिए PriorityQueueअधिक उपयुक्त नाम होगा।
सोलो

ओपी एक संग्रहणीय संग्रह चाहता है जो डुप्लिकेट कुंजियों की अनुमति देता है। आपकी कक्षा एक संग्रह नहीं है , क्योंकि यह गणना नहीं की जा सकती है। मैं सार्वजनिक क्षेत्रों के उपयोग को भी नापसंद करता हूं। व्यक्तिगत रूप से पतन न करें। आप एकल अपवोट ( -2 * 5 == +10) के साथ 5 डाउनवोट्स की प्रतिष्ठा को नुकसान पहुंचा सकते हैं , इसलिए यह कोई बड़ी बात नहीं है। :-)
थियोडोर ज़ूलियास
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.