यदि किसी सूची में सभी मान अद्वितीय हैं तो परीक्षण करें


90

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

List<byte> theList = new List<byte> { 1,4,3,6,1 };

यह जांचने का सबसे अच्छा तरीका है कि सभी मान अलग-अलग हैं या नहीं?


2
जैसा कि यह एक विशिष्ट क्लास रूम प्रश्न है, मैं एक प्रश्न के साथ उत्तर दूंगा। यदि इसे क्रमबद्ध किया जाता तो आप इसे कैसे करते?
— ctrl-alt-delor

जवाबों:


168
bool isUnique = theList.Distinct().Count() == theList.Count();

बस जिज्ञासु: इस की जगह और समय की आवश्यकताएं क्या हैं?
— dtb

10
@dtb O (N) के बारे में होना चाहिए । बेशक, यह "छोटी सूची" है, इस पर विचार करना लगभग किसी भी एल्गोरिथ्म के साथ बिजली की तेजी से होगा। IMO यह पठनीयता और संक्षिप्तता पर जीतता है, और चूंकि गति कोई मुद्दा नहीं है, इसलिए यह इसे सही बनाता है।
— टिम एस।

2
यह जितना हो सकता है उससे कहीं अधिक कुशल है
— जोडरेल

74

यहां एक और दृष्टिकोण है जो Enumerable.Distinct+ से अधिक कुशल है Enumerable.Count(सभी अधिक अगर अनुक्रम संग्रह प्रकार नहीं है)। यह HashSet<T>डुप्लिकेट को समाप्त करने वाले का उपयोग करता है , लुकअप में बहुत कुशल है और इसकी गिनती संपत्ति है:

var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;

या अन्य - अधिक सूक्ष्म और कुशल - दृष्टिकोण:

var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);

HashSet<T>.Addfalseयदि तत्व पहले से ही इसमें शामिल नहीं है तो रिटर्न देता है HashSet। Enumerable.Allपहले "झूठे" पर रुक जाता है।


1
इतना सरल और स्पष्ट, मैंने पहले इसके बारे में क्यों नहीं सोचा :) मैंने अपने भयानक कोड द्वारा उत्पन्न 10 मिलियन तत्वों की पुष्टि करने के लिए यूनिट टेस्ट में इस वन-लाइनर का उपयोग किया है जो वास्तव में अद्वितीय हैं Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));। वे आप के लिए :) +1 थे और टिम :)
— grapkulec

1
मैंने इस प्रश्न पर आपके उत्तर की कोशिश की है लेकिन यह काम नहीं कर रहा है सर: stackoverflow.com/questions/34941162/…
— लर्निंग-ओवरथिंकर-कन्फ्यूज्ड

यह होना चाहिए:bool allDifferent = theList.All(s => diffChecker.Add(s))
— माइक नेल्सन

2
नहीं, जरूरत नहीं। इस मामले में आप सीधे प्रतिनिधि को पास कर सकते हैं
— टिम श्मेल्टर

1
@ AndréReichelt - मैंने अभी आपका कोड खोला है और तीसरा परिदृश्य ( List.All(HashSet.Add)) लगभग सभी मामलों में अन्य दो की तुलना में बहुत तेज है
— काइल डेलाने

6

ठीक है, यहां सबसे कुशल तरीका है जो मैं मानक .Net का उपयोग करने के बारे में सोच सकता हूं

using System;
using System.Collections.Generic;

public static class Extension
{
    public static bool HasDuplicate<T>(
        this IEnumerable<T> source,
        out T firstDuplicate)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        var checkBuffer = new HashSet<T>();
        foreach (var t in source)
        {
            if (checkBuffer.Add(t))
            {
                continue;
            }

            firstDuplicate = t;
            return true;
        }

        firstDuplicate = default(T);
        return false;
    }
}

अनिवार्य रूप से, पूरे अनुक्रम को दो बार एन्यूमरेट करने का क्या मतलब है यदि आप सभी करना चाहते हैं तो पहला डुप्लिकेट ढूंढें।

मैं इसे एक खाली और एकल तत्व अनुक्रमों को विशेष रूप से कवर करके अधिक अनुकूलित कर सकता हूं, लेकिन यह न्यूनतम लाभ के साथ पठनीयता / स्थिरता से मूल्यह्रास करेगा।


डुप्लिकेट वैल्यू आउट रिटर्न को जोड़कर, सत्यापन के लिए काफी उपयोगी है
— Pac0

मैंने यहां 3 समाधानों का परीक्षण किया है और यह वास्तव में इस पृष्ठ पर सबसे अधिक कुशल है। हालांकि वहाँ कुछ टाइपो (जैसे sequenceहोना चाहिए source)। लेकिन जब ये तय हो जाते हैं तो बढ़िया काम करता है
— माइक नेल्सन

@ मिकेनेलसन, जो बेहतर होना चाहिए
— जोडरेल

2
पठनीयता के लिए, मुझे लगता है कि यह if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }लूप में होना चाहिए ।
— तिया

2

Distinctउपयोग करने के लिए समान तर्क GroupBy:

var isUnique = theList.GroupBy(i => i).Count() == theList.Count;

यह उपयोगी है यदि आप किसी संपत्ति के संबंध में विशिष्टता की जांच करना चाहते हैं theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;जबकि डिस्टिक्ट () इसकी अनुमति नहीं देता है।
— Rev1.0

1

एक भी कर सकते हैं: हैशसेट का उपयोग करें

var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));

            if (uniqueIds.Count != originalList.Count)
            {
            }

0

कई उपाय हैं।

और LINQ के "juergen d" और "टिम श्मेल्टर" के रूप में उल्लेख के साथ और अधिक सुंदर लोगों पर कोई संदेह नहीं है।

लेकिन, यदि आप "जटिलता" और गति को नंगे करते हैं, तो सबसे अच्छा उपाय यह होगा कि आप इसे स्वयं लागू करें। समाधान में से एक होगा, एन आकार की एक सरणी बनाने के लिए (बाइट के लिए यह 256)। और सरणी को लूप करें, और प्रत्येक पुनरावृत्ति मिलान संख्या सूचकांक का परीक्षण करेगा यदि मान 1 है तो यह करता है, इसका मतलब है कि मैं पहले से ही सरणी सूचकांक बढ़ाता हूं और इसलिए सरणी भिन्न नहीं है अन्यथा मैं सरणी सेल बढ़ाऊंगा और जांच जारी रखूंगा ।


2
आप 256 बिट्स = 32 बाइट = 8 पूर्णांक के साथ एक बिट वेक्टर का उपयोग कर सकते हैं। लेकिन आपका बिग O = O (n) अभी भी वैसा ही होगा जैसा कि दूसरे उत्तर में प्रस्तावित हैशेट का उपयोग करना है।
— BrokenGlass

यह O (n) है तो शायद सबसे तेज़, (इसे परखें)। के रूप में आप जाते हैं या अंत में सबसे तेज जाँच मायने रखता है? मुझे संदेह है कि अंत में सबसे खराब स्थिति में सुधार होगा, लेकिन जैसा कि आप जाते हैं औसत और सर्वोत्तम मामले में सुधार कर सकते हैं)। यदि कोई डुप्लिकेट नहीं है तो यह सबसे खराब स्थिति होगी। इसके अलावा बड़े डेटा प्रकारों के लिए यह अच्छी तरह से काम नहीं करेगा, 16 बिट प्रकार के लिए आपको 64k गिनती, अच्छी तरह से 64k बिट (8k बाइट) का उपयोग करना होगा, लेकिन किसी भी बड़ी चीज के लिए मेमोरी का उपयोग मूर्खतापूर्ण होना शुरू हो जाएगा। हालाँकि मुझे यह 8 बिट मूल्यों के लिए उत्तर पसंद है।
— ctrl-alt-delor

1
@TamusJRoyce यदि आप 4294967296 संभावनाओं को स्टोर करना चाहते हैं, तो आपको 4GB की आवश्यकता नहीं है 42MB (या 512MB आप बिट मास्किंग का उपयोग करें)
— tigrou

निश्चित नहीं कि मैं क्या सोच रहा था। "सभी 4294967296 संभावनाओं को रखने के लिए 42MB + मेमोरी का आवंटन करें। और साधारण बाल्टी काउंटर का उपयोग करें। या फिर बिट मास्किंग एक्सर का उपयोग करें और जांचें कि क्या कोई बिट सही से गलत में बदल गया है। 42MB + / 8 = 5MB + + खर्च आज के हार्डवेयर के साथ बहुत अच्छा लगता है। लेकिन एक दिन यह योग्यता हो सकती है। " वास्तव में एक प्रासंगिक टिप्पणी नहीं है। हैशसेट सबसे अच्छा होगा। यदि आप बहुत बड़ी सरणियों के साथ काम कर रहे हैं, तो आप स्मृति के बहुत बड़े टुकड़े की अपेक्षा करते हैं। लेकिन इस तरह के एक अजीब मामले में, सीआरसी एल्गोरिथ्म के साथ एक विधर्मी बेहतर होगा। इसे एक बहुपद में मैप करें। यदि पास है, तो मूल्यांकन करें। शुक्रिया @tigrou!
— TamusJRoyce

0

और दूसरा उपाय, यदि आप डुप्लिकेट किए गए मानों को खोजना चाहते हैं।

var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };

var sorted = values.ToList();
sorted.Sort();
for (var index = 1; index < sorted.Count; index++)
{
    var previous = sorted[index - 1];
    var current = sorted[index];
    if (current == previous)
        Console.WriteLine(string.Format("duplicated value: {0}", current));
}

आउटपुट:

duplicated value: 2
duplicated value: 7

http://rextester.com/SIDG48202


0

अगर कोई IEnumerable (क्षय, सूची, आदि) इस तरह अद्वितीय है मैं जाँच करता हूँ:

var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.