Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumerator stuck in endless loop when removing excess items from a List

Tags:

c#

linq

do-while

I have a script that takes an int[] array, converts it to a list and removes all further occurrences of the integers that already occurred at least 2 times. The problem I have is that when it gets into the loop where I am checking the count of each integers occurrences, I am getting stuck in a loop.

EDIT: "What I left out was that the list has to remain in its original order so that excess numbers are removed from top down. Sorry if that confused those who already answered!

I thought that the changed number of the occursintegerOccurrence would act as a change of count for the while loop.

Any ideas on what I'm missing here? Aside from any discernible skill.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;

public class Kata
{
    public static void Main()
    {
       int[] arr = new int[] {1, 2, 1, 4, 5, 1, 2, 2, 2};
        int occurrenceLimit = 2;
       var intList = arr.ToList();

        for (int i = 0; i < intList.Count; i++)
        {
            var occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);

            do
            {
                occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);
                foreach (var x in intList)
                {
                    Console.WriteLine(x);
                    intList.Remove(intList.LastIndexOf(occurrenceLimit));
                    // Tried changing the count here too
                    occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);
                }
            } while (occursintegerOccurrence > occurrenceLimit);
        }
    }
}
like image 598
3therk1ll Avatar asked Dec 05 '22 17:12

3therk1ll


2 Answers

Here's a fairly concise version, assuming that you want to remove all instances of integers with a count in excess of 2, leaving the remainder of the bag in its original sequence, with preference to retention traversing from left to right:

int[] arr = new int[] {1, 2, 1, 4, 5, 1, 2, 2, 2};
var ints = arr.Select((n, idx) => new {n, idx})
               .GroupBy(x => x.n)
               .SelectMany(grp => grp.Take(2))
               .OrderBy(x => x.idx)
               .Select(x => x.n)
               .ToList();

Result:

1, 2, 1, 4, 5, 2

It works by using the index overload of Select to project an anonymous Tuple and carrying through the original order to allow re-ordering at the end.

like image 67
StuartLC Avatar answered Dec 08 '22 11:12

StuartLC


The cause of the endless loop is the line

 intList.Remove(intList.LastIndexOf(occurrenceLimit));

..you are removing the value equals to the last occurence in the list of the occurrenceLimit value(=2), that it is "8" (the last index of the array counting from 0).

Since "8" it isn't present in the list, you don't remove anything and the loop permanence test doesn't ever change and so it is always verified and the loop never ends..

This method works for any values of occurrenceLimit but I think that the solution of StuartLC is better..

int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int?[] arr2 = new int?[arr.Length];
arr2.ToList().ForEach(i => i = null);
int occurrenceLimit = 2;

var ints = arr.GroupBy(x => x).Select(x => x.Key).ToList();

ints.ForEach(i => {
   int ndx = 0;
   for (int occ = 0; occ < occurrenceLimit; occ++){
        ndx = arr.ToList().IndexOf(i, ndx);
        if (ndx < 0) break;
        arr2[ndx++] = i;
   }
});

List<int?> intConverted = arr2.ToList();
intConverted.RemoveAll(i => i.Equals(null));
like image 22
Ciro Corvino Avatar answered Dec 08 '22 12:12

Ciro Corvino