Тізімдегі <> C # ішіндегі көшірмелерді болдырмаудың жылдам жолдары

My C# бағдарламасы берілген үлгіден кездейсоқ жолдарды жасайды. Бұл жолдар тізімде сақталады. Ешқандай қайталанбауға рұқсат етілмегендіктен, мен бұны:

List myList = new List();
for (int i = 0; i < total; i++) {
  string random_string = GetRandomString(pattern);
  if (!myList.Contains(random_string)) myList.Add(random_string);
}

Бұл бірнеше жүздеген жазбалар үшін жақсы жұмыс істейтінін елестетіп көріңіз. Бірақ бірнеше миллион жолды қалыптастыру үшін жағдайға тап болдым. Әрбір қосымша жолмен қайталауға арналған тексерулер баяу әрі баяуырақ болады.

Көшірмелерді болдырмаудың жылдам жолы бар ма?

21
@Jonesy: Бұл белгілі бір деректер жинағы үшін тестілеуге тұрарлық нәрсе сияқты. Егер ол жылдамырақ болса, онда кодты қосатын (бұл жағдайда көп болмайтын) кодсыздандыруға қарсы өнімділікті оңтайландыруды өлшейді.
қосылды автор David, көзі
олардың бәрі жылдамырақ болар ма еді, содан кейін қайталанатындарды тексеру үшін Distinct() пайдаланыңыз, содан кейін жойылған нөмірді қосыңыз?
қосылды автор Jonesopolis, көзі
Қызығушылық танытқаннан кейін, дәл сіз оларды не үшін пайдаланасыз?
қосылды автор musefan, көзі
@Servy: Әділетті жеткілікті, сіз, мүмкін, дұрыс, ол, әрине, логикалық естіледі
қосылды автор musefan, көзі
@Servy: Қақтығыстың қаншалықты мүмкін екеніне байланысты. Егер бағдарлама Тізімді бірінші кезекте DB жүктеп алу керек болса, ол қолайлы сауда-саттық болуы мүмкін.
қосылды автор musefan, көзі
Егер сіздің тізіміңізді дерекқорға қалдырсаңыз, сіз сондай-ақ өрісті бірегей етіп жасауға тырысыңыз және INSERT сәтсіздікке ұшыраған жағдайда басқа біреуді көре аласыз - тек басқа нәрсе
қосылды автор musefan, көзі
Өкінішке орай, @Servy жоқ. Үлгі ерекше болып табылады, сондықтан GUID көмектеспейді.
қосылды автор Robert Strauch, көзі
@musefan Маған құжаттарға арналған сериялық нөмірлерді жасау керек.
қосылды автор Robert Strauch, көзі
@musefan Бұрынғы жол бар екенін білу үшін бүкіл DB айналымын орындау ... мәселе болады.
қосылды автор Servy, көзі
@musefan Элементтің ЖБ-да бұрыннан бар-жоғын анықтау үшін бірыңғай DB сұрауын жасау, тіпті элементтің жадтағы хэшсетінде бар-жоғын тексеру үшін миллиондаған тексерулер болмаса, жүздеген мыңнан көп уақыт алады. Осы проблеманы шешуге арналған ДБ-ны пайдалану бірнеше мың есе төмендеуді жеңілдетуі мүмкін.
қосылды автор Servy, көзі
@Robert Әрбір құжат үшін GUID қолдануға бола ма?
қосылды автор Servy, көзі
телнұсқаларын болдырмау үшін жиынтығын пайдаланыңыз
қосылды автор Jayram Singh, көзі
@David Мүмкін, HashSet бастапқыда аз еске әсерінен тезірек болатынына және кейінірек оны қайталаудың қажеті болмағандықтан теориялық дәлел жасай алатын шығармын. Әрбір элементті тексеру құны әлі де бар, бірақ ол үшін деректер құрылымы оңтайландырылған.
қосылды автор Adam Houldsworth, көзі

7 жауаптар

Элемент бар ма әлде барынша тиімді түрде анықталатын деректер құрылымын, яғни HashSet . Ол жиынтықтағы элементтердің санына қарамастан элементті тұрақты уақыт ішінде орнатылғанын анықтай алады.

Егер орнына шынымен керек болса List ішіндегі элементтерге қажет болса немесе нәтиже тізіміндегі элементтер қажет болған тәртіпте болуы қажет болса, онда сіз деректерді тізім және хэшсет; HashSet ішіндегі қазіргі кезде жоқ болса, элементті екі жиынға қосыңыз.

35
қосылды
Жарайды, сондықтан HashSet қолдандым және жылдамдықтың ұлғаюы зор. Бірақ менде жаңа мәселе бар. Хеш жинағында жазбалардың белгілі бір саны қажет. Егер менің сұрағым үшін «loop» үшін пайдалансам, онда ол 2 000 000 циклнан кейін тоқтайды. Көшірмелер хеште жоқ, бірақ егер көшірме хеш жинағына кірсе, 2,000,000 жазбалары болмайды. Бұдан қалай аулақ бола аламын? if (myList.Count <2000000) myList.Add (random_string); бұны болдырмайды, бірақ қайтадан баяу.
қосылды автор Robert Strauch, көзі
@Robert үшін (int i = 0; i орнына үшін (int i = 0; set.Count қолданыңыз. Немесе, шынымен i керек емес болса, онда while (set.Count .
қосылды автор Servy, көзі
бұл HasSet үшін элементті табу O (1), сондықтан егер сіз бұл тауарды тапсаңыз = оны бірқалыпты тізімге қосыңыз.
қосылды автор user2545071, көзі

Don't use List<>. Use Dictionary<> or HashSet<> instead!

9
қосылды
HashSet-ты пайдалану арқылы сіз Тізіммен қалай болатындығыңызға қол жеткізе алмайсыз және нысанды өзгерте алмайсыз.
қосылды автор ppumkin, көзі

Ең оңай тәсілі - бұл:

myList = myList.Distinct().ToList();

Бұл тізімді бір рет жасауды талап етсе де, жаңа тізім жасау керек. Генераторды мерзімінен бұрын жасаудың жақсы жолы болуы мүмкін:

public IEnumerable GetRandomStrings(int total, string pattern)
{
    for (int i = 0; i < total; i++) 
    {
        yield return GetRandomString(pattern);
    }
}

...

myList = GetRandomStrings(total, pattern).Distinct().ToList();

Әрине, егер индекстер бойынша элементтерге қатынасудың қажеті болмаса, ToList және IEnumerable дегенді пайдалану арқылы тиімділікті одан да арттыра аласыз.

5
қосылды
Тізімдегі бірнеше миллион жолдарды жою үшін . Бірегей пайдалану тиімді IMO деп саналмайды.
қосылды автор Darren Davies, көзі
Сондай-ақ, нәтиже қажет жолдың бірнеше саны болса, GetRandomStrings болуы шексіз ұзын тізбекті қалыптастырып, кейін оны Take қолданыңыз. қалаған өлшемі. Жасалған жолдар санын немесе бірегей Take Take немесе Distinct > Жасалынған жолдар.
қосылды автор Servy, көзі
@ p.s.w.g Мен өзіңіздің getRandomStrings әдісін yield деген жолды ғана қабылдаймын, оны жергілікті жерге қойып қана қоймай, оны тастаңыз.
қосылды автор Servy, көзі
@DarrenDavies ішіндегі Distinct , басқалар ұсынғандай, HashSet пайдаланады. Жалғыз тиімсіз бөлігі алдымен тізімді қалыптастырады, содан кейін жауапты екінші бөлікте айтқанымнан ерекшелігі бар.
қосылды автор p.s.w.g, көзі
@Servy Иә, рахмет.
қосылды автор p.s.w.g, көзі
@Servy Мен оны бастапқыда іске асырдым, бірақ шексіз генераторлар қауіпті болуы мүмкін және кейбір күтіммен айналысу керек.
қосылды автор p.s.w.g, көзі

You could use a HashSet if order is not important:

HashSet myHashSet = new HashSet();
for (int i = 0; i < total; i++) 
{
   string random_string = GetRandomString(pattern);
   myHashSet.Add(random_string);
}

HashSet класы жоғары сапалы жиынтық әрекеттерді қамтамасыз етеді. Жиын - қайталанбайтын элементтері жоқ және элементтері нақты тәртіпте жоқ топтама.

MSDN

Немесе тәртібі маңызды болса, SortedSet (тек .net 4.5)

5
қосылды
Содан кейін қылқан зат қалай аламын? HashSet GET-ге ие емес, өзіңді іске асыру өте тиімді емес.
қосылды автор ppumkin, көзі
SortedSet элементтерді сұрыптайды. Егер реттелген жиынтығы талап етілсе (яғни элемент реті сақталса) OrderedDictionary - бұл жақсы таңдау. Қиындықтар - ол жалпы емес.
қосылды автор Olivier Jacot-Descombes, көзі

жақсы тәсіл емес, тез түзету түрі, толық тізімде қайталанатын жазбаның бар-жоғын тексеру үшін босатыңыз.

bool containsKey;
string newKey;

    public void addKey(string newKey){

         foreach(string key in MyKeys){
           if(key == newKey){
             containsKey = true;
          }
         }

      if(!containsKey){
       MyKeys.add(newKey);
     }else{
       containsKey = false;
     }

    }
1
қосылды

Hashtable элементі тізімнен әлде қайда бар екенін тексерудің жылдам жолы болар еді.

0
қосылды
Оның кілттік/құндылықтық қатынастары жоқ, жай ғана жолдар тізбегі, сондықтан ол жиынтығын картаға қажет етпейді. Сонымен қатар, HashTable жалпы емес; Егер сіз шынымен картаның құрылымы қажет болса, оның орнына жалпы Сөздік пайдалану керек. HashTable-ді бұрынғы кодта пайдаланбаңыз.
қосылды автор Servy, көзі

Сіз көріңіз:

myList = myList.Distinct()
0
қосылды