1
\$\begingroup\$

I would like to convert a list A

A = {1, 12, 3, 3, 3, 8, 5, 5 }

into list B

B = {1, 12, 3, 8, 5 }

As you see, items 3 and 5 are repeated in A, and those repetitions are eliminated in B.

The code I've created to do that is the following:

public IEnumerable<int> FilterRepeatingElements(IEnumerable<int> source) 
{
    return source
        .Select(x => (IEnumerable<int>)new[] { x })
        .Aggregate((a, b) => a.Last() != b.First() ? a.Concat(b) : a);
}

It works, but I wonder if there's a better more expressive way to do it using "LINQ", either with the classic .NET methods or the ones in a library like morelinq.

Thanks!

EDIT

I have found out that my solution has problem with uses case like this:

FilterRepeatingElements(MoreEnumerable.Random()).Take(10)
  • MoreEnumerable.Random() generates an infinite sequence. Executing code like this, hangs the execution.
\$\endgroup\$
6
  • 2
    \$\begingroup\$ You cannot make a finite set of unique elements of an infinite series. There is no way around it (well in general, for the specific case of int data type you can, at the cost of memory proportional to number of possible values of int). Anyway for finite inputs you can use a set like HashSet or linq offers the Distinct method. \$\endgroup\$ – slepic Feb 14 at 18:00
  • \$\begingroup\$ @slepic non-unique != repetions? \$\endgroup\$ – aepot Feb 14 at 21:18
  • \$\begingroup\$ docs.microsoft.com/en-us/dotnet/api/… \$\endgroup\$ – BCdotWEB Feb 15 at 8:00
  • \$\begingroup\$ Can you please clarify whether the repetition you want to avoid is just for elements repeating in a row, or repeating ever? i.e. is {3,4,3} valid or not? \$\endgroup\$ – Turksarama Feb 15 at 12:34
  • \$\begingroup\$ maybe this is related : codereview.stackexchange.com/questions/61338/… \$\endgroup\$ – iSR5 Feb 15 at 14:32
3
\$\begingroup\$

While aepot answer is a good answer and got my upvote it does only work for type int. Which I know the question for an example uses int in their code but if wanting it to work for all data types will need to change the code a bit.

public static class EnumerableExtensions
{
    public static IEnumerable<TSource> FilterRepeatingElements<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
    {
        using (var enumerator = source.GetEnumerator())
        {
            if (enumerator.MoveNext())
            {
                var item = enumerator.Current;
                yield return item;

                while (enumerator.MoveNext())
                {
                    if (!comparer.Equals(item, enumerator.Current))
                    {
                        item = enumerator.Current;
                        yield return item;
                    }
                }
            }
        }
    }

    public static IEnumerable<TSource> FilterRepeatingElements<TSource>(this IEnumerable<TSource> source)
    {
        return FilterRepeatingElements(source, EqualityComparer<TSource>.Default);
    }
}

This would work for any type and takes the same parameters as linq Distinct does since we are doing a "kind of" distinct.

var data = new int[] { 1, 12, 3, 3, 3, 8, 5, 5 };
var postData = data.FilterRepeatingElements().ToArray();

var items = new string[] { "A", "A", "B", "C", "C", "D", "D" };
var postItems = items.FilterRepeatingElements().ToArray();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.