Click here to Skip to main content
13,148,427 members (65,408 online)
Rate this:
 
Please Sign up or sign in to vote.
See more:
Today's coding challenge is pretty loose in terms of how you approach it and how you interpret the problem.

Given a collection of items (integers, strings, objects - whatever) determine the set of subitems in that collection that are repeated.

For example
{1,2,3,3,4,5,5,6} => {3,5}


Points are awarded for elegance, speed, and excessive use of complicated logic. Over engineering the solution will gain you favours.

Last week's winner was Peter Leow, mainly because Graeme_Grant is killing it and I wanted to award a new player. Graeme's Delphi solution brought a tear to my eye. Peter: contact Sean for a trinket.
Posted 10-Feb-17 3:17am
Updated 17-Feb-17 19:37pm
Comments
Graeme_Grant 10-Feb-17 9:54am
   
I guess that was a compliment of sorts ... I've enjoyed learning a new retro language... kinda makes me wish I had spent more time with it sooner... Previous week was the first time that I had and no one else participated ... bit of a bummer really...
Maciej Los 17-Feb-17 8:29am
   
Chris,
Can you tell me the most important idea of coding challenge? Till now, i've been sure that the most important thing is to provide one unconventional solution, but now i see that coding chalenge has been changed into "How many programming languages you know?". I'd suggest to post the rules of coding challenge. If the method of resolving issue is the same (the same idea), the count of solutions couldn't be the reason of glory (upvotes).
Note: i see nothing wrong with six or more solutions of Graeme_Grant: F#, Linq and non-Linq version of C# and VB.NET, PowerShell, BatchScript, WPF(?!?), but... it stinks of bragging.
Chris Maunder 17-Feb-17 22:15pm
   
>now i see that coding chalenge has been changed into "How many programming languages you know?".
No - it's not that at all. A single answer is all I'm after. The single most *interesting* answer. The one that provokes the most discussion, the most praise, the most enjoyment. The one that shows someone stretched themselves a little more than the others. That's what it's about.
Graeme_Grant 17-Feb-17 23:45pm
   
This has given me the opportunity to learn 3 new languages (F#, Powershell, Free Pascal) where I would not have normally bothered. It has been an interesting and fun journey.

VB is where I came from. So as for C#/VB, not everyone programs in C#. When I have the time I attach a VB version for those who don't.

Thanks Chris for doing these! :)
Maciej Los 18-Feb-17 10:34am
   
Chris, thanks for explanation.

Graeme, forgive me if i offended you. It wasn't my intention. I started my programming journey with Pascal and VBA. I have got medium experience with C++. Now, i'm using VB.NET and C# (prefered). As you can see, i'd be able to provide 5 solutions, but the idea to resolve issue would be the same. So, i'd rather to provide one solution (in any language). That's my point of view.

Cheers,
Maciej
Graeme_Grant 18-Feb-17 10:43am
   
It would be good to see you partake in these challenges. There is a new one active now[^]...
Maciej Los 19-Feb-17 6:05am
   
I've been there ;)
Graeme_Grant 19-Feb-17 6:11am
   
Yes... 1 out of 11 challenges... How about the current one?
Maciej Los 19-Feb-17 6:22am
   
My philosophical nature says: do i have to take a part in competitions?
:laugh:
pwasser 19-Feb-17 20:51pm
   
Would one solution per member be a worthwhile constraint.
Graeme_Grant 24-Feb-17 18:07pm
   
I always expect only my first solution to be judged.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 4

Here is my quick solution... Tests done are for nulls List, List elements including nulls, using List elements of Int, String, and complex Object (Car).

Update: Added F# conversion of C# and VB.Net.

Pick your poison... ummm.. language - F#, C#, or VB.Net. There are also Powershell (solution 9) & Batch script (solution 12) versions below. Or if like to visualise, there is a WPF (solution 11) version that you can try and it will update highlighting in realtime.


let GetRepeats items = 
        let GetRepeatsHelper (x, y) item = 
            if x |> Set.contains item 
                then (x, y |> Set.add item) 
                else (x |> Set.add item, y)
        List.fold GetRepeatsHelper (Set.empty, Set.empty) items |> snd

public static IEnumerable<T> GetRepeats<T>(this List<T> items) 
    => items?.Intersect(items.Where(x => items.Where(y => Equals(x, y)).Count() > 1));

<Extension>
Public Function GetRepeats(Of T)(items As List(Of T)) As IEnumerable(Of T)
    Return If(items Is Nothing, Nothing, items.Intersect(items.Where(Function(x) items.Where(Function(y) Equals(x, y)).Count() > 1)))
End Function

Here is a complete solution with test cases:


open System
 
type Car(brand:string, model:string, year:int) = 
    member this.Brand = brand
    member this.Model = model
    member this.Year = year
    override x.Equals(y) =
        match y with
        | :? Car as z -> (x.Brand = z.Brand && x.Model = z.Model && x.Year = z.Year)
        | _ -> false
    override x.GetHashCode() = hash (sprintf "%s%s%i" x.Brand x.Model x.Year)
    interface System.IComparable with
      member x.CompareTo y =
          match y with
          | :? Car as z -> compare (sprintf "%s%s%i" x.Brand x.Model x.Year) (sprintf "%s%s%i" z.Brand z.Model z.Year)
    override m.ToString() = sprintf "%i %s %s" m.Year m.Brand m.Model
 
let GetRepeats items = 
        let GetRepeatsHelper (x, y) item = 
            if x |> Set.contains item 
                then (x, y |> Set.add item) 
                else (x |> Set.add item, y)
        List.fold GetRepeatsHelper (Set.empty, Set.empty) items |> snd
 
let FormatResult items repeats = 
    let FormatSet items =
        items |> Set.map (sprintf "%A") |> String.concat ", "
    sprintf "For [ %s ]\r\n > %s" (FormatSet items) ( if Seq.isEmpty repeats then sprintf "There are no repeats" else sprintf "Has [ %s ] elements repeated" (FormatSet repeats))
 
[<EntryPoint>]
let main argv = 
 
    printfn "Find Repeated Items in a Collection of Elements"
    printfn "==============================================="
 
    let emptyTest = [null]
    let intTest = [1; 2; 3; 3; 4; 5; 5; 6;]
    let stringTest = ["apples"; "oranges"; "mangos"; "apples"; "peaches"; "pineapples"; "mangos"]
    let objTest = [new Car("Mazda", "CX9",2016); new Car("Ford", "XR5",2014); new Car("Ford", "XR5",2010); new Car("Holden", "Commodore",2015); new Car("Mazda", "CX9",2016) ]
 
    printfn "%s\r\n" (FormatResult (emptyTest |> Set.ofList) (GetRepeats emptyTest))
    printfn "%s\r\n" (FormatResult (intTest |> Set.ofList) (GetRepeats intTest))
    printfn "%s\r\n" (FormatResult (stringTest |> Set.ofList) (GetRepeats stringTest))
    printfn "%s\r\n" (FormatResult (objTest |> Set.ofList) (GetRepeats objTest))
    
    printfn"\r\n-- Press any key to exit --";
    Console.ReadKey() |> ignore;
    0

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace FindRepeats
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> empty1Test = null;
            var empty2Test = new List<int>();
            var intTest = new List<int>() { 1, 2, 3, 3, 4, 5, 5, 6 };
            var stringTest = new List<string>() { "apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos" };
            var objTest = new List<Car>()
            {
                new Car() { Brand="Mazda", Model="CX9",Year=2016 },
                new Car() {Brand="Ford", Model="XR5",Year=2014 },
                new Car() {Brand="Ford", Model="XR5",Year=2010 },
                new Car() {Brand="Holden", Model="Commodore",Year=2015 },
                new Car() { Brand="Mazda", Model="CX9",Year=2016 },
                null
            };
 
            Console.WriteLine("Find Repeated Items in a Collection of Elements");
            Console.WriteLine("===============================================");
            Console.WriteLine($"\r\n{empty1Test.FormatResult(empty1Test.GetRepeats())}");
            Console.WriteLine($"\r\n{empty2Test.FormatResult(empty2Test.GetRepeats())}");
            Console.WriteLine($"\r\n{intTest.FormatResult(intTest.GetRepeats())}");
            Console.WriteLine($"\r\n{stringTest.FormatResult(stringTest.GetRepeats())}");
            Console.WriteLine($"\r\n{objTest.FormatResult(objTest.GetRepeats())}");
 
            Console.WriteLine("\r\n-- Press any key to exit --");
            Console.ReadKey();
        }
 
    }
 
    public static class HelperExtension
    {
        public static IEnumerable<T> GetRepeats<T>(this List<T> items) 
            => items?.Intersect(items.Where(x => items.Where(y => Equals(x, y)).Count() > 1));
 
        public static string FormatResult<T>(this List<T> items, IEnumerable<T> repeats) 
            => $"For [ {(items == null ? "" : string.Join(", ", items))} ]\r\n > {(repeats == null || !repeats.Any() ? "There are no repeats" : $"Has [ {string.Join(", ", repeats)} ] elements repeated")}";
    }
 
    public class Car : IEquatable<Car>
    {
        public string Brand { get; set; }
        public string Model { get; set; }
        public int Year { get; set; }
 
        public override string ToString() 
            => $"{Year} {Brand} {Model}";
 
        public override int GetHashCode()
        {
            int hash = 17;
            hash = hash * 31 + Brand.GetHashCode();
            hash = hash * 31 + Model.GetHashCode();
            hash = hash * 31 + Year.GetHashCode();
            return hash;
        }
 
        public override bool Equals(object o) 
            => o == null ? false : Equals(o as Car);
 
        public bool Equals(Car car) 
            => Brand == car.Brand && Model == car.Model && Year == car.Year;
    }
}

Imports System.Runtime.CompilerServices
 
Module Module1
 
    Sub Main()
        Dim empty1Test As List(Of Integer) = Nothing
        Dim empty2Test = New List(Of Integer)()
        Dim intTest = New List(Of Integer)() From {1, 2, 3, 3, 4, 5, 5, 6}
        Dim stringTest = New List(Of String)() From {"apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos"}
        Dim objTest = New List(Of Car)() From
        {
                New Car() With {.Brand = "Mazda", .Model = "CX9", .Year = 2016},
                New Car() With {.Brand = "Ford", .Model = "XR5", .Year = 2014},
                New Car() With {.Brand = "Ford", .Model = "XR5", .Year = 2010},
                New Car() With {.Brand = "Holden", .Model = "Commodore", .Year = 2015},
                New Car() With {.Brand = "Mazda", .Model = "CX9", .Year = 2016},
                Nothing ' null element test
        }
 
        Console.WriteLine("Find Repeated Items in a Collection of Elements")
        Console.WriteLine("===============================================")
        Console.WriteLine(vbCrLf & "{0}", empty1Test.FormatResult(empty1Test.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", empty2Test.FormatResult(empty2Test.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", intTest.FormatResult(intTest.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", stringTest.FormatResult(stringTest.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", objTest.FormatResult(objTest.GetRepeats()))
 
        Console.WriteLine(vbCrLf & "-- Press any key to exit --")
        Console.ReadKey()
    End Sub
 
End Module
 
Public Module HelperExtensions
 
    <Extension>
    Public Function GetRepeats(Of T)(items As List(Of T)) As IEnumerable(Of T)
        Return If(items Is Nothing, Nothing, items.Intersect(items.Where(Function(x) items.Where(Function(y) Equals(x, y)).Count() > 1)))
    End Function
 
    <Extension>
    Public Function FormatResult(Of T)(items As List(Of T), repeats As IEnumerable(Of T)) As String
        Return String.Format("For [ {0} ]" & vbCrLf & " > {1}", If(items Is Nothing, "", String.Join(", ", items)), If(repeats Is Nothing OrElse Not repeats.Any(), "There are no repeats", String.Format("Has [ {0} ] elements repeated", String.Join(", ", repeats))))
    End Function
 
End Module
 
Public Class Car : Implements IEquatable(Of Car)
 
    Public Property Brand As String
    Public Property Model As String
    Public Property Year As Integer
 
    Public Overrides Function ToString() As String
        Return String.Format("{0} {1} {2}", Year, Brand, Model)
    End Function
 
    Public Overrides Function GetHashCode() As Integer
        Dim hash As Long = 17
        hash = hash * 31 + Brand.GetHashCode()
        hash = hash * 31 + Model.GetHashCode()
        hash = hash * 31 + Year.GetHashCode()
        Return CInt(hash And &H7FFFFFFFL)
    End Function
 
    Public Overrides Function Equals(o As Object) As Boolean
        Return If(o Is Nothing, False, EqEquals(o))
    End Function
 
    Public Function EqEquals(car As Car) As Boolean Implements IEquatable(Of Car).Equals
        Return Brand = car.Brand AndAlso Model = car.Model AndAlso Year = car.Year
    End Function
 
End Class

Update #2: Here is a non-Linq version for both C# & VB versions:


public static IEnumerable<T> GetRepeats<T>(this List<T> items)
{
    if (items == null || items.Count == 0) yield break;
    items.Sort(); T c = items[0]; int n = 0;
    for (int i = 1; i < items.Count; i++)
    {
        if (!items[i].Equals(c))
        {
            c = items[i];
            n = 0;
        }
        else
            n++;
        if (n == 1) yield return c;
    }
}

<Extension>
Public Iterator Function GetRepeats(Of T)(items As List(Of T)) As IEnumerable(Of T)
    If items Is Nothing OrElse items.Count = 0 Then
        Return
    End If
    items.Sort()
    Dim c As T = items(0)
    Dim n As Integer = 0
    For i As Integer = 1 To items.Count - 1
        If Not items(i).Equals(c) Then
            c = items(i)
            n = 0
        Else
            n += 1
        End If
        If n = 1 Then
            Yield c
        End If
    Next
End Function

Here is a complete solution with test cases:


using System;
using System.Collections.Generic;
 
namespace FindRepeats
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> empty1Test = null;
            var empty2Test = new List<int>();
            var intTest = new List<int>() { 1, 2, 3, 3, 4, 5, 5, 6 };
            var stringTest = new List<string>() { "apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos" };
            var objTest = new List<Car>()
            {
                new Car() { Brand="Mazda", Model="CX9",Year=2016 },
                new Car() {Brand="Ford", Model="XR5",Year=2014 },
                new Car() {Brand="Ford", Model="XR5",Year=2010 },
                new Car() {Brand="Holden", Model="Commodore",Year=2015 },
                new Car() { Brand="Mazda", Model="CX9",Year=2016 },
                null
            };
 
            Console.WriteLine("Find Repeated Items in a Collection of Elements");
            Console.WriteLine("===============================================");
            Console.WriteLine($"\r\n{empty1Test.FormatResult(empty1Test.GetRepeats())}");
            Console.WriteLine($"\r\n{empty2Test.FormatResult(empty2Test.GetRepeats())}");
            Console.WriteLine($"\r\n{intTest.FormatResult(intTest.GetRepeats())}");
            Console.WriteLine($"\r\n{stringTest.FormatResult(stringTest.GetRepeats())}");
            Console.WriteLine($"\r\n{objTest.FormatResult(objTest.GetRepeats())}");
 
            Console.WriteLine("\r\n-- Press any key to exit --");
            Console.ReadKey();
        }
 
    }
 
    public static class HelperExtension
    {
        public static IEnumerable<T> GetRepeats<T>(this List<T> items)
        {
            if (items == null || items.Count == 0) yield break;
            items.Sort(); T c = items[0]; int n = 0;
            for (int i = 1; i < items.Count; i++)
            {
                if (!items[i].Equals(c))
                {
                    c = items[i];
                    n = 0;
                }
                else
                    n++;
                if (n == 1) yield return c;
            }
        }
 
        public static string FormatResult<T>(this List<T> items, IEnumerable<T> repeats)
        {
            string a = string.Empty;
            string b = string.Empty;
            string c = string.Empty;
            var sb = new StringBuilder();
 
            if (items != null)
                a = items.ListToString();
 
            if (repeats.HasResults() == false)
                b = "There are no repeats";
            else
            {
                c = repeats.ListToString();
                b = string.Format("Has [ {0} ] elements repeated", c);
            }
            sb.AppendFormat("For [ {0} ]", a);
            sb.AppendLine();
            sb.AppendFormat(b);
            return sb.ToString();
        }
 
        public static bool HasResults<T>(this IEnumerable<T> items)
        {
            if (items == null) return false;
            int i = 0;
            using (var s = items.GetEnumerator())
                while(s.MoveNext())
                {
                    i++;
                    if (i > 0) return true;
                }
            return false;
        }
 
        public static string ListToString<T> (this IEnumerable<T> items)
        {
            var result = new StringBuilder("");
            if (items != null)
                using(IEnumerator<T> s = items.GetEnumerator())
                    while(s.MoveNext())
                        result.AppendFormat("{0}, ", s.Current);
            return result.ToString().TrimEnd(new[] { ' ', ',' });
        }
    }
 
    public class Car : IEquatable<Car>, IComparable<Car>
    {
        public string Brand { get; set; }
        public string Model { get; set; }
        public int Year { get; set; }
 
        public override string ToString()
            => $"{Year} {Brand} {Model}";
 
        public override int GetHashCode()
        {
            int hash = 17;
            hash = hash * 31 + Brand.GetHashCode();
            hash = hash * 31 + Model.GetHashCode();
            hash = hash * 31 + Year.GetHashCode();
            return hash;
        }
 
        public override bool Equals(object o)
            => o == null ? false : Equals(o as Car);
 
        public bool Equals(Car car)
            => Brand == car.Brand && Model == car.Model && Year == car.Year;
 
        public int CompareTo(Car y)
            => y == null ? 1 :
               Year.CompareTo(y.Year) != 0 ? Year.CompareTo(y.Year) :
               Brand.CompareTo(y.Brand) != 0 ? Brand.CompareTo(y.Brand) :
               Model.CompareTo(y.Model) != 0 ? Model.CompareTo(y.Model) : 0;
    }                                             
}

Imports System.Runtime.CompilerServices
Imports FindRepeatsVB
 
Module Module1
 
    Sub Main()
        Dim empty1Test As List(Of Integer) = Nothing
        Dim empty2Test = New List(Of Integer)()
        Dim intTest = New List(Of Integer)() From {1, 2, 3, 3, 4, 5, 5, 6}
        Dim stringTest = New List(Of String)() From {"apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos"}
        Dim objTest = New List(Of Car)() From
        {
                New Car() With {.Brand = "Mazda", .Model = "CX9", .Year = 2016},
                New Car() With {.Brand = "Ford", .Model = "XR5", .Year = 2014},
                New Car() With {.Brand = "Ford", .Model = "XR5", .Year = 2010},
                New Car() With {.Brand = "Holden", .Model = "Commodore", .Year = 2015},
                New Car() With {.Brand = "Mazda", .Model = "CX9", .Year = 2016},
                Nothing ' null element test
        }
 
        Console.WriteLine("Find Repeated Items in a Collection of Elements")
        Console.WriteLine("===============================================")
        Console.WriteLine(vbCrLf & "{0}", empty1Test.FormatResult(empty1Test.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", empty2Test.FormatResult(empty2Test.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", intTest.FormatResult(intTest.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", stringTest.FormatResult(stringTest.GetRepeats()))
        Console.WriteLine(vbCrLf & "{0}", objTest.FormatResult(objTest.GetRepeats()))
 
        Console.WriteLine(vbCrLf & "-- Press any key to exit --")
        Console.ReadKey()
    End Sub
 
End Module
 
Public Module HelperExtensions
 
    <Extension>
    Public Iterator Function GetRepeats(Of T)(items As List(Of T)) As IEnumerable(Of T)
        If items Is Nothing OrElse items.Count = 0 Then
            Return
        End If
        items.Sort()
        Dim c As T = items(0)
        Dim n As Integer = 0
        For i As Integer = 1 To items.Count - 1
            If Not items(i).Equals(c) Then
                c = items(i)
                n = 0
            Else
                n += 1
            End If
            If n = 1 Then
                Yield c
            End If
        Next
    End Function
 
    <Extension>
    Public Function FormatResult(Of T)(items As List(Of T), repeats As IEnumerable(Of T)) As String
        Return String.Format("For [ {0} ]" & vbCrLf & " > {1}", If(items Is Nothing, "", String.Join(", ", items)), If(repeats Is Nothing OrElse Not repeats.GetEnumerator().MoveNext(), "There are no repeats", String.Format("Has [ {0} ] elements repeated", String.Join(", ", repeats))))
    End Function
End Module
 
Public Class Car : Implements IEquatable(Of Car), IComparable(Of Car)
    Public Property Brand As String
    Public Property Model As String
    Public Property Year As Integer
 
    Public Overrides Function ToString() As String
        Return String.Format("{0} {1} {2}", Year, Brand, Model)
    End Function
 
    Public Overrides Function GetHashCode() As Integer
        Dim hash As Long = 17
        hash = hash * 31 + Brand.GetHashCode()
        hash = hash * 31 + Model.GetHashCode()
        hash = hash * 31 + Year.GetHashCode()
        Return hash And &H7FFFFFFFL
    End Function
 
    Public Overrides Function Equals(o As Object) As Boolean
        Return If(o Is Nothing, False, EqEquals(o))
    End Function
 
    Public Function EqEquals(car As Car) As Boolean Implements IEquatable(Of Car).Equals
        Return Brand = car.Brand AndAlso Model = car.Model AndAlso Year = car.Year
    End Function
 
    Public Function CompareTo(y As Car) As Integer Implements IComparable(Of Car).CompareTo
        Return If(y Is Nothing, 1,
               If(Year.CompareTo(y.Year) <> 0, Year.CompareTo(y.Year),
               If(Brand.CompareTo(y.Brand) <> 0, Brand.CompareTo(y.Brand),
               If(Model.CompareTo(y.Model) <> 0, Model.CompareTo(y.Model), 0))))
    End Function
 
End Class

Update #3: Here is non-Linq version #2, based off the Batch script (solution 12) for both C# & VB versions:


public static IEnumerable<T> GetRepeats<T>(this List<T> items)
{
    if (items == null || items.Count == 0) yield break;
    var r = new List<T>();
    int i, j, k, l = i = k = l = 0, c = items.Count;
a1: j = i;
a2: if (i == j) goto a3;
    if (items[i].Equals(items[j])) goto a4;
a3: if (++j < c) goto a2;
    if (++i < c) goto a1;
    goto a7;
a4: if (k == 0)
    {
        k = 1;
        r.Add(items[i]);
        yield return items[i];
        goto a3;
    }
    l = 0;
a5: if (r.Count > 0 && items[j].Equals(r[l])) goto a3;
    if (++l == k) goto a6;
    goto a5;
a6: r.Add(items[i]);
    yield return items[i];
    goto a3;
a7: ;
}

<Extension>
Public Iterator Function GetRepeats(Of T)(items As List(Of T)) As IEnumerable(Of T)
    If items Is Nothing OrElse items.Count = 0 Then
        Return
    End If
    Dim r = New List(Of T)(), c As Integer = items.Count
    Dim i As Integer, j As Integer, k As Integer, l As Integer
    i = k = l = 0
a1: j = i
a2: If i = j Then GoTo a3
    If items(i).Equals(items(j)) Then GoTo a4
a3: j += 1
    If j < c Then GoTo a2
    i += 1
    If i < c Then GoTo a1
    GoTo a7
a4: If k = 0 Then
        k = 1
        r.Add(items(i))
        Yield items(i)
        GoTo a3
    End If
    l = 0
a5: If r.Count > 0 AndAlso items(j).Equals(r(l)) Then GoTo a3
    l += 1
    If l = k Then GoTo a6
    GoTo a5
a6: r.Add(items(i))
    Yield items(i)
    GoTo a3
a7:
End Function

And the output for all samples:
Find Repeated Items in a Collection of Elements
===============================================
 
For [  ]
 > There are no repeats
 
For [  ]
 > There are no repeats
 
For [ 1, 2, 3, 3, 4, 5, 5, 6 ]
 > Has [ 3, 5 ] elements repeated
 
For [ apples, oranges, mangos, apples, peaches, pineapples, mangos ]
 > Has [ apples, mangos ] elements repeated
 
For [ 2016 Mazda CX9, 2014 Ford XR5, 2010 Ford XR5, 2015 Holden Commodore, 2016 Mazda CX9 ]
 > Has [ 2016 Mazda CX9 ] elements repeated
 
-- Press any key to exit --
And here is a special "PIEBALDconsult formated" version of the C# non-Linq solution Extension Methods (extra over-engineering included):
public static class HelperExtension
{
    public static
    System.Collections.Generic.IEnumerable < T > 
    GetRepeats < T >
    (
        this System.Collections.Generic.List < T > items
    )
    {
        if ( items == null || items.Count == 0 )
        {
            yield break  ;
        }
 
        items.Sort ()  ;
 
        T c = items [ 0 ]  ;
 
        int n = 0  ;
 
        for ( int i = 1 ; i < items.Count ; i ++ )
        {
            if ( ! items [ i ].Equals ( c ) )
            {
                c = items [ i ]  ;
                n = 0  ;
            }
            else
            {
                n ++  ;
            }
 
            if ( n == 1 )
            {
                yield return c  ;
            }
        }
    }
 
    public static 
    string 
    FormatResult < T >
    ( 
        this System.Collections.Generic.List < T > items , 
        System.Collections.Generic.IEnumerable < T > repeats
    )
    {
        string a = string.Empty  ;
        string b = string.Empty  ;
        string c = string.Empty ;
 
        System.Text.StringBuilder sb = new System.Text.StringBuilder () ;
 
        if ( items != null )
        {
            a = items.ListToString () ;
        }
 
        if ( repeats.HasResults () == false )
        {
            b = "There are no repeats"  ;
        }
        else
        {
            c = repeats.ListToString () ;
            b = string.Format ( "Has [ {0} ] elements repeated", c )  ;
        }
 
        sb.AppendFormat ( "For [ {0} ]" , a ) ;
        sb.AppendLine () ;
        sb.AppendFormat ( b ) ;
 
        return sb.ToString () ;
    }
 
    public static
    bool
    HasResults < T >
    (
        this System.Collections.Generic.IEnumerable < T > items
    )
    {
        if ( items == null )
        {
            return false  ;
        }
 
        int i = 0  ;
 
        using
        (
            System.Collections.Generic.IEnumerator < T > s = items.GetEnumerator ()
        )
        {
            while
            (
                s.MoveNext ()
            )
            {
                i ++ ;
 
                if ( i > 0 )
                {
                    return true ;
                }
            }
        }
 
        return false  ;
    }
 
    public static 
    string
    ListToString < T >
    (
    this System.Collections.Generic.IEnumerable < T > items
    )
    {
        System.Text.StringBuilder result = new System.Text.StringBuilder ( "" ) ;
        if ( items != null )
        {
            using
            (
                System.Collections.Generic.IEnumerator < T > s = items.GetEnumerator ()
            )
            {
                while
                (
                    s.MoveNext ()
                )
                {
                    result.AppendFormat ( "{0}, " , s.Current ) ;
                }
            }
        }
 
        return result.ToString ().TrimEnd ( new [] { ' ' , ',' } ) ;
    }
}
VB.Net & F# are pretty strict on formatting, so no special "PIEBALDconsult formating" applied.
  Permalink  
v20
Comments
Richard Deeming 10-Feb-17 11:44am
   
What if the sequence contains null?

And how many times are you iterating over the list? :P
Graeme_Grant 10-Feb-17 11:52am
   
Works fine. ;) will be updating with test code as well.
Richard Deeming 10-Feb-17 11:56am
   
Are you sure? :P

Testing in LINQPad:
var items = new List<string> { "A", "A", null };
items.GetRepeats().Dump();

->
NullReferenceException
 at Extensions.<>c__DisplayClass0_1`1.<GetRepeats>b__1(T y)
 at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
 at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)
 at Extensions.<>c__DisplayClass0_0`1.<GetRepeats>b__0(T x)
 at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
 at System.Linq.Enumerable.<IntersectIterator>d__69`1.MoveNext()
Graeme_Grant 10-Feb-17 12:00pm
   
run the demo and see... The first null check items?. will stop the error you see in LinqPad from occuring.
Richard Deeming 10-Feb-17 12:03pm
   
But you haven't got a demo with a null item in the list. :)
Graeme_Grant 10-Feb-17 12:05pm
   
Sorry, but... List<int> empty1Test = null; and var empty2Test = new List<int>();
Richard Deeming 10-Feb-17 12:07pm
   
No, that's "a null list", not "a list with a null item in it". :)

Try it with new List<string> { "A", "A", null };
Graeme_Grant 10-Feb-17 12:09pm
   
was not part of the requirement...
Richard Deeming 10-Feb-17 12:11pm
   
But it wasn't not part of the requirement either! :D
Graeme_Grant 10-Feb-17 12:13pm
   
Just for you Richard I will make a small change. Happy?
Richard Deeming 10-Feb-17 12:20pm
   
That's better. :D
Graeme_Grant 10-Feb-17 14:33pm
   
Want to debug my F# code as well? ;)
Graeme_Grant 10-Feb-17 14:33pm
   
Want to debug my F# code as well? ;)
Richard Deeming 10-Feb-17 14:41pm
   
Looks good to me. :D
Graeme_Grant 10-Feb-17 14:45pm
   
This is my 3rd attempt at F# ... not a language of choice! ;)
Graeme_Grant 13-Feb-17 7:27am
   
I posted a PowerShell version if you want to debug that too... ;)
Richard Deeming 10-Feb-17 11:58am
   
Hint: Try replacing: y.Equals(x)
with: Equals(y, x)
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 7

Late to the party; never mind. You want over-engineered? Here we go. The Heath-Robinson* nature of this "solution" is merely a bonus. :D

*For USAnian readers : Rube Goldberg.

Pseudo-code only 'cos life's too short to actually bother building this rubbish.

1. Buy server.

2. Buy RDMBS license

3. Install RDMBS on server

4. Create DB in RDMBS

5. In your DB create a table:
duplicates (
 testId varchar(xx),
 itemAsString varchar
 constraint PK_makeItCrash primary key (testId, itemAsString)
)


6. Write code to insert string version of item to table

string testId = getUniqueIdentifier();  // To allow multiple simultaneous runs
foreach(item in set) {
  string flat = serializeAsJSON(item); // Serialize according to method du jour.
  try {
    writeToRDMBS(testId, flat);
  }
  catch (duplicate key exception)
  {
    writeToConsole(item);
  }
 }
 clearDownTable(testId);


Of course this reports every attempted insertion so if you've n, where n>2, copies of items you'll get n-1 reports of duplication.

A slightly less bonkers, yes... well.., solution would be to dump the PK constraint, insert all items and then run a standard SQL query to get the flattened duplicates from the table and reinflate them.

-- Not guaranteed to be correct. It's the weekend and I'm a couple of coffees short of quota.
select count(itemAsString), itemAsString from [duplicates] group by itemAsString having count(itemAsString) > 1 
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

Here's the obvious, under-complicated, under-engineered C# solution:
public static class Extensions
{
    public static IEnumerable<T> FindDuplicates<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (comparer == null) comparer = EqualityComparer<T>.Default;
        
        var seenItems = new HashSet<T>(comparer);
        var duplicates = new HashSet<T>(comparer);
        foreach (T item in source)
        {
            if (!seenItems.Add(item) && duplicates.Add(item))
            {
                yield return item;
            }
        }
    }
}

The down-side is, it needs to keep a copy of every distinct item from the input sequence in memory. With an extremely large input sequence, you could potentially get an OutOfMemoryException.


EDIT: Option 2, using a Dictionary<T, byte>, as suggested by PIEBALDconsult:
public static class Extensions
{
    public static IEnumerable<T> FindDuplicates<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (comparer == null) comparer = EqualityComparer<T>.Default;
        
        var items = new Dictionary<T, byte>(comparer);
        byte nullCount = 0;
        
        foreach (T item in source)
        {
            if (item == null)
            {
                switch (nullCount)
                {
                    case 0:
                    {
                        nullCount = 1;
                        break;
                    }
                    case 1:
                    {
                        nullCount = 2;
                        yield return item;
                        break;
                    }
                }
            }
            else
            {
                byte count;
                if (!items.TryGetValue(item, out count))
                {
                    items.Add(item, 1);
                }
                else if (count == 1)
                {
                    yield return item;
                    items[item] = 2;
                }
            }
        }
    }
}
  Permalink  
v4
Comments
PIEBALDconsult 10-Feb-17 10:56am
   
Surely, you're maintaining only _references_ to the items.
And I expect that two Hashsets is overkill.
Richard Deeming 10-Feb-17 11:00am
   
For reference types, yes. You can still hit an "out of memory" exception if the HashSet<T> gets too large.
Richard Deeming 10-Feb-17 11:47am
   
Two hashsets would be overkill if you didn't care about duplicates in the output.

Since we're looking for the "set" of repeated items, that implies we do care, and we only want each duplicated item to appear once. :)
PIEBALDconsult 10-Feb-17 11:58am
   
I find that a Dictionary works better.
Richard Deeming 10-Feb-17 12:07pm
   
OK, I've added a variation using a dictionary. Happy now? :)
Chris Maunder 10-Feb-17 11:01am
   
"With an extremely large input sequence, you could potentially get an OutOfMemoryException" Therein lies the challenge. The simple answer is easy. It's when things get a little crazy that separates the Men from the boys.
Maciej Los 14-Feb-17 16:30pm
   
Looks good to me and your solution is more generic than others ;)
Graeme_Grant 14-Feb-17 20:58pm
   
How is it more generic? Also, It will fail if there is a null element ...
An unhandled exception of type 'System.NullReferenceException' occurred
Maciej Los 15-Feb-17 1:50am
   
In a short: because of usage IEqualityComparer<T>, so any of data type can be used.
Graeme_Grant 15-Feb-17 2:06am
   
It is only required for complex-objects/classes. What his solution does not show is that you still have to override GetHashCode and Equals on each class object for it to work - without the overrides, the IEqualityComparer<T> will not work.

I do the same thing in Solution 4. The only difference, as I demonstrate, is that I set it for the class so that it will work with any internal .Net sorting or compare mechanism that uses a default comparer. This still allows for custom comparers to be used *if* required. Doing it this way allows me to uses classes with Linq or List.Sort() as I do in Solution 4... You can see the results from the sample tests that I provide in the solution.

The one thing that this solution does offer is injecting a custom comparer but still has the same requirements as above. Custom sorting is not a requirement of this challenge.
Richard Deeming 15-Feb-17 7:58am
   
The IEqualityComparer<T> interface has nothing to do with custom sorting. You're thinking of the IComparer<T> interface.

And if you provide a custom IEqualityComparer<T> instance, you do not have to override GetHashCode and Equals. You only need to override those if you're using the default equality comparer.
Graeme_Grant 15-Feb-17 8:01am
   
I have tested and it failed with POCOs... I can post the test online if you want.
Richard Deeming 15-Feb-17 8:07am
   
Works fine for me:
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
 
public class PersonAgeEqualityComparer : IEqualityComparer<Person>
{
    public int GetHashCode(Person person) => person?.Age ?? 0;
    public bool Equals(Person left, Person right) => left?.Age == right?.Age;
}
 
var items = new[] 
{ 
    new Person { Name = "A", Age = 1 },
    new Person { Name = "B", Age = 1 },
    new Person { Name = "C", Age = 2 },
};
 
items.FindDuplicates().Dump(); // No items
items.FindDuplicates(new PersonAgeEqualityComparer()).Dump(); // Returns "B"
Graeme_Grant 15-Feb-17 8:13am
   
I can see that it will work for simple cases, but not for more complex real-world cases when working with inherited classes. But for this challenge it does the job.
Richard Deeming 15-Feb-17 8:17am
   
Why would there be a problem with inherited classes?

Either the class defines its own rules for equality by overriding GetHashCode and Equals; or the custom IEqualityComparer<T> provides the rules for equality.

Dealing with inherited classes is more complicated in both cases, but not impossible in either. :)
Maciej Los 15-Feb-17 9:36am
   
Well... a challenge has been defined as: Given a collection of items (...whatever) determine the set of subitems in that collection that are repeated. So, there must be some way to compare objects. IEqualityComparer seems to be the best way for object's comparison.
Graeme_Grant 15-Feb-17 9:55am
   
I did not say that comparing objects was not part of the challenge, I said: "Custom sorting is not a requirement of this challenge". But Richard & I have discussed his implementation as you have already read...
Richard Deeming 15-Feb-17 7:56am
   
The first option will not fail if there is a null element.

The second option will, but with an ArgumentNullException from the dictionary, not a NullReferenceException.
Graeme_Grant 15-Feb-17 8:00am
   
Are you sure... I can post the test online if you want.

[edit:] I can see that you just modified your code to fix it.
Richard Deeming 15-Feb-17 8:03am
   
Yes, I'm sure.
var items = new[] { "hello", null, "hello", null, "goodbye" };
items.FindDuplicates().Dump();

Output from option 1:
{ "hello", null }

Output from (fixed) option 2:
{ "hello", null }
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 6

Here is an memory improved version BetterDuplicated. I've kept the old Duplicated method for comparison. The new version require that the input be a List so it can be sorted.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Challenge
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> input = new List<int>{ 1, 2, 3, 3, 4, 5, 5, 6 };
            var duplicatedItems = BetterDuplicated(input);
            if (duplicatedItems.Count() == 0)
                Console.WriteLine("No Duplicates");
            else
                Console.WriteLine($"Duplicated items: {{{string.Join(",", input)}}} => {{{string.Join(",", duplicatedItems)}}}");
 
            Console.ReadLine();
        }
 
        // Determine the duplicated items by gouping equal values and filtering for groups that
        // have more than one item.
        static public IEnumerable<T> Duplicated<T>(IEnumerable<T> source)
        {
            return source
                .GroupBy(x => x)
                .Where(g => g.Count() > 1)
                .Select(g => g.Key);
        }
 
        // A 'Better' implementation that shouldn't allocate much extra memory.
        // Determine the duplicated items by gouping equal values and filtering for groups that
        // have more than one item.
        static public IEnumerable<T> BetterDuplicated<T>(List<T> source)
        {
            T currentItem = default(T);
            int count = 0;
            source.Sort();
            foreach (T item in source)
            {
                if (!item.Equals(currentItem))
                {
                    currentItem = item;
                    count = 0;
                }
 
                count++;
 
                if (count == 2)
                    yield return item;
            }
        }
    }
}
  Permalink  
v2
Comments
Graeme_Grant 10-Feb-17 23:49pm
   
Hey Matthew, I just posted an updated non-Linq version of my code (like I did last week) without first checking what others had posted. I have just noticed that our solutions are almost identical! The only difference is that yours will fail if there is a null element ...
An unhandled exception of type 'System.NullReferenceException' occurred
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

Last code of the day before going to bed:
class Employee:
    def __init__(self, name):
        self.name = name
 
employee1 = Employee("Trump")
    
employee2 = Employee("Obama")
 
mixed_list = ["m", "b", None, "m", "x", "x", "a", "c", 3, None, 1, 2, 3, 4, 5, 6, 5, employee1, employee1, employee2]
 
print('A list of mixed types {}'.format(mixed_list))
 
item_count_dict = {i:mixed_list.count(i) for i in mixed_list}
 
print('Dictionary of items and their counts {}'.format(item_count_dict))
 
plural_list = [key for key, value in item_count_dict.items() if value > 1]
 
print('The repeated items {}'.format(plural_list))
check out the demo at Coding challenge: find the repeated items in a collection of elements, Python 3[^] and the output as follows:
A list of mixed types ['m', 'b', None, 'm', 'x', 'x', 'a', 'c', 3, None, 1, 2, 3, 4, 5, 6, 5, <__main__.Employee object at 0x7fa45044c470>, <__main__.Employee object at 0x7fa45044c470>, <__main__.Employee object at 0x7fa45044c5f8>]
Dictionary of items and their counts {1: 1, None: 2, 3: 2, 4: 1, 5: 2, 6: 1, <__main__.Employee object at 0x7fa45044c470>: 2, 'c': 1, 2: 1, 'x': 2, 'a': 1, 'b': 1, 'm': 2, <__main__.Employee object at 0x7fa45044c5f8>: 1}
The repeated items [None, 3, 5, <__main__.Employee object at 0x7fa45044c470>, 'x', 'm']

Woke up with a growling stomarch, that reminded me to feed None (null in Python) to the list, updated the solution and off for my breakfast.
  Permalink  
v8
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 3

An excuse to fire up VS 2017 RC :).

Assuming that the items can be compared for equality then
using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Challenge
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] input = { 1, 2, 3, 3, 4, 5, 5, 6 };
            var duplicatedItems = Duplicated(input);
            if (duplicatedItems.Count() == 0)
                Console.WriteLine("No Duplicates");
            else
                Console.WriteLine($"Duplicated items: {{{string.Join(",", input)}}} => {{{string.Join(",", duplicatedItems)}}}");
 
            Console.ReadLine();
        }
 
        // Determine the duplicated items by gouping equal values and filtering for groups that
        // have more than one item.
        static public IEnumerable<T> Duplicated<T>(IEnumerable<T> source)
        {
            return source
                .GroupBy(x => x)
                .Where(g => g.Count() > 1)
                .Select(g => g.Key);
        }
    }
}

which results in

Duplicated items: {1,2,3,3,4,5,5,6} => {3,5}
  Permalink  
v2
Comments
Richard Deeming 10-Feb-17 11:42am
   
That's going to end up storing a reference to every item in the input sequence. I suspect yours will hit the OutOfMemory exception earlier than mine. :)
Matthew Dennis 10-Feb-17 11:51am
   
True, but then I would be processing a Huge data set and would be using something a little more complex that would allow for parallel processing of the data. Possibly Sort and Scan for duplicates. That would require the items to be Comparable as well as Equatable.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 5

public partial class ListIndex<T> 
{
  private readonly System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<int>> map ;
 
  public ListIndex
  (
    System.Collections.Generic.ICollection<T> Input
  )
  {
    this.map = new System.Collections.Generic.Dictionary<T,System.Collections.Generic.List<int>>() ;
 
    if ( Input != null )
    {
      int i = 0 ;
 
      foreach ( T t in Input )
      {
        if ( !this.map.ContainsKey ( t ) )
        {
          this.map [ t ] = new System.Collections.Generic.List<int>() ;
        }
 
        this.map [ t ].Add ( i ) ;
 
        i++ ;
      }
    }
 
    return ;
  }
 
  public System.Collections.Generic.IEnumerable<System.Tuple<T,System.Collections.Generic.IList<int>>>
  Duplicates
  {
    get
    {
      foreach ( System.Collections.Generic.KeyValuePair<T,System.Collections.Generic.List<int>> kvp in this.map )
      {
        if ( kvp.Value.Count > 1 )
        {
          yield return ( new System.Tuple<T,System.Collections.Generic.IList<int>>
          (
            kvp.Key
          ,
            kvp.Value.AsReadOnly()
          ) ) ;
        }
      }
 
      yield break ;
    }
  }
}



ListIndex<int> li = new ListIndex<int> ( new int[] { 1 , 2 ,  3 , 3 , 4 , 5 , 5 , 6 } ) ;
 
foreach ( System.Tuple<int,System.Collections.Generic.IList<int>> dup in li.Duplicates )
{
  System.Console.WriteLine ( "{0} appears {1} times" , dup.Item1 , dup.Item2.Count ) ;
}
  Permalink  
v2
Comments
Graeme_Grant 10-Feb-17 15:14pm
   
Can it handle more than ints? Classes maybe?
PIEBALDconsult 10-Feb-17 19:33pm
   
It ought to. Depends on how the type is defined. I leave all the heavy lifting up to the Dictionary, so blame Microsoft if it doesn't work. :shrug:
Graeme_Grant 11-Feb-17 0:10am
   
Just ran it and it does support objects however, it will fail if there is a null element ...
An unhandled exception of type 'System.NullReferenceException' occurred
Here is a link to the test project[^] (with odd formatting removed) that was used...
PIEBALDconsult 11-Feb-17 0:18am
   
Don't care.
The spec says "collection of items" -- a NULL _should_ result in an Exception.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 8

<html>
<head>
<title>CPCC: Find the repeated items in a collection of elements.</title>
</head>
<body>
<?php
    $arr = array(1, 2, 3, 3, 4, 5, 5, 6);
    $dup = array();
    
    foreach(array_count_values($arr) as $val => $cnt) {
        if($cnt > 1) {
            $dup[] = $val;
        }
    }
        
    echo print_r($dup, true);
?>
</body>
</html>
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 9

I thought that I would try PowerShell again - 2nd attempt with this script language. I am still new to it, so please be kind...

Here is a quick pure native PowerShell version...
function GetRepeats { param ($l)
	$l | group -Property {$_.ToString()} | where-object {$_.count -gt 1} | Foreach {"$($_.name)"}
}
Here is a complete solution with test cases:
function New-Car { param ([String] $Brand, [String] $Model, [Int] $Year)
	New-Module { param ( $br, $mo, $yr )
		[String] $Brand = $br
		[String] $Model = $mo
		[Int] $Year = $yr
		function ToString { "$Year $Brand $Model" }
		Export-ModuleMember -Variable Brand, Model, Year -Function ToString
	} -AsCustomObject -ArgumentList $Brand, $Model, $Year
}
 
function GetRepeats { param ($l)
	$l | group -Property {$_.ToString()} | where-object {$_.count -gt 1} | Foreach {"$($_.name)"}
}
 
function FormatResult {
	param ($l, $r)
	$ls = $l | & {$ofs=', ';"$input"}
	if ($r -eq $null -or $r.Count -eq 0) { 
		$msg = "There are no repeats" 
	}
	else {
		$rs = $r | & {$ofs=', '; "$input"}
		$msg = "Has [ $rs ] elements repeated"
	}
	"`r`nFor [ $ls ]`r`n > $msg"
}
function Main {
	$empty1Test = $null
	$empty2Test = New-Object List[int]
	$intTest = (1, 2, 3, 3, 4, 5, 5, 6)
	$stringTest = ("apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos")
	$Cars = 
	(
		(New-Car -Brand Mazda -Model CX9 -Year 2016),
		(New-Car -Brand Ford -Model XR5 -Year 2014),
		(New-Car -Brand Ford -Model XR5 -Year 2010),
		(New-Car -Brand Holden -Model Commodore -Year 2015),
		(New-Car -Brand Mazda -Model CX9 -Year 2016)
	)
	$mixedTest =
	(
		1, 2, 3, 3, 4, 5, 5, 6,
		"apples", "oranges", "mangos", "apples", "peaches", "pineapples", "mangos",
		(New-Car -Brand Mazda -Model CX9 -Year 2016),
		(New-Car -Brand Ford -Model XR5 -Year 2014),
		(New-Car -Brand Ford -Model XR5 -Year 2010),
		(New-Car -Brand Holden -Model Commodore -Year 2015),
		(New-Car -Brand Mazda -Model CX9 -Year 2016),
		$null
	)
 
	echo "Find Repeated Items in a Collection of Elements"
	echo "==============================================="
	FormatResult -l $empty1Test -r (GetRepeats -l $empty1Test)
	FormatResult -l $empty2Test -r (GetRepeats -l $empty2Test)
	FormatResult -l $intTest -r (GetRepeats -l $intTest)
	FormatResult -l $stringTest -r (GetRepeats -l $stringTest)
	FormatResult -l $Cars -r (GetRepeats -l $Cars)
	FormatResult -l $mixedTest -r (GetRepeats -l $mixedTest)
}
 
Main


And the output:
Find Repeated Items in a Collection of Elements
===============================================
 
For [  ]
 > There are no repeats
 
For [  ]
 > There are no repeats
 
For [ 1, 2, 3, 3, 4, 5, 5, 6 ]
 > Has [ 3, 5 ] elements repeated
 
For [ apples, oranges, mangos, apples, peaches, pineapples, mangos ]
 > Has [ apples, mangos ] elements repeated
 
For [ 2016 Mazda CX9, 2014 Ford XR5, 2010 Ford XR5, 2015 Holden Commodore, 2016 Mazda CX9 ]
 > Has [ 2016 Mazda CX9 ] elements repeated
 
For [ 1, 2, 3, 3, 4, 5, 5, 6, apples, oranges, mangos, apples, peaches, pineapples, mangos, 2016 Mazda CX9, 2014 Ford XR5, 2010 Ford XR5, 2015 Holden Commodore, 2016 Mazda CX9,  ]
 > Has [ 3, 5, apples, mangos, 2016 Mazda CX9 ] elements repeated
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 10

Here is one using c++, templates and stl sort(). For non built in types the operator< is overloaded to enable a sort and the operator== is overloaded for comparisons. The class person allows modification of the class itself for the overrides. If this is not possible external overrides are employed and the compiler chooses the correct one. This is shown using the class PERSON

#include "stdafx.h"
#include <iostream>     
#include <vector>
#include <algorithm>
using namespace std;
 
template <class Atype>
void findDupes(vector<Atype> &data)
{
	vector<Atype> dupes;
 
	// Put all the dupes next to each other.
	sort(data.begin(), data.end());
 
	vector<Atype>::iterator it = data.begin();
	auto lastVal = *it++;
 
	for (it; it != data.end(); it++) {
		if (lastVal == *it) {		// Is it a dupe?
			dupes.push_back(*it);	// Add to dupes vector.
									// Jump over any repeats.
			for(it; it != data.end() - 1 && lastVal == *it; it++)
				;
		}
		lastVal = *it;
	}
 
	for (auto &&A : dupes) {
		print(A);	// Print dupes.
	}
}
 
class person
{
public:
	string name;
	char gender;
	int age;
 
	inline bool operator== (const person &p1) const
	{
		return (age == p1.age &&
			gender == p1.gender && name == p1.name);
	}
 
	inline bool operator< (const person &p1) const
	{
		if (name < p1.name) return true;
		if (name > p1.name) return false;
		if (gender < p1.gender) return true;
		if (gender > p1.gender) return false;
		if (age < p1.age) return true;
		if (age > p1.age) return false;
		return false;
	}
};
 
class PERSON
{
public:
	PERSON(const string NAME, const char GENDER, const int AGE)
	{ name = NAME; gender = GENDER; age = AGE; };
	string getName() const { return name; };
	char getGender() const { return gender; };
	int getAge() const { return age; };
 
private:
	string name;
	char gender;
	int age;
};
 
inline bool operator== (const PERSON &p1, const PERSON &p2)
{
	return (p1.getAge() == p2.getAge() &&
		p1.getGender() == p2.getGender() && p1.getName() == p2.getName());
}
 
inline bool operator< (const PERSON &p1, const PERSON &p2)
{
	if (p1.getName() < p2.getName()) return true;
	if (p1.getName() > p2.getName()) return false;
	if (p1.getGender() < p2.getGender()) return true;
	if (p1.getGender() > p2.getGender()) return false;
	if (p1.getAge() < p2.getAge()) return true;
	if (p1.getAge() > p2.getAge()) return false;
	return false;
}
 
void print(const person &p1)
{
	std::cout << "Name: " << p1.name.c_str() <<
		", Gender: " << p1.gender <<
		", Age: " << p1.age << "\n";
}
 
void print(const PERSON &p1)
{
	std::cout << "Name: " << p1.getName().c_str() <<
		", Gender: " << p1.getGender() <<
		", Age: " << p1.getAge() << "\n";
}
 
void print(const string &val)
{
	std::cout << "String: " << val.c_str() << "\n";
}
 
void print(const int &val)
{
	std::cout << "Int: " << val << "\n";
}
 
void print(const double &val)
{
	std::cout << "Double: " << val << "\n";
}
 
int main()
{
	vector<int> numcp = { 1, 2, 3, 3, 4, 5, 5, 6 };
	vector<int> numints = { 2,2,2,2,2,2,3,3,3,3,3,3,7,7,3,4,5,5,6,1,2,3 };
	vector<double> numdoubls = { 2.2,2.3,2.4,2.5,2.6,2.6,3,3.3,3.3,
		3,3,3,7,7,3,4,5,5,6,1,2.2,3 };
	vector<string> textstrings = { "test1", "test2", "test3", "test1" };
	vector<person> persons = { { "Bill", 'M', 45 }, { "Bill", 'M', 46 },
	{"Harry", 'M', 45},{ "Marg", 'F', 55 },{ "Marg", 'F', 45 },
	{ "Bill", 'M', 45 },{ "Marg", 'X', 55 } };
	vector<PERSON> PERSONS = { { "Bill", 'M', 45 },{ "Bill", 'M', 46 },
	{ "Harry", 'M', 45 },{ "Marg", 'F', 55 },{ "Marg", 'F', 45 },
	{ "Bill", 'M', 45 },{ "Marg", 'X', 55 } };
 
	findDupes(numcp);
	std::cout << "\n";
	findDupes(numints);
	std::cout << "\n";
	findDupes(numdoubls);
	std::cout << "\n";
	findDupes(textstrings);
	std::cout << "\n";
	findDupes(persons);
	std::cout << "\n";
	findDupes(PERSONS);
 
	cin.get();
	return 0;
}


Output:
Int: 3
Int: 5

Int: 2
Int: 3
Int: 5
Int: 7

Double: 2.2
Double: 2.6
Double: 3
Double: 3.3
Double: 5
Double: 7

String: test1

Name: Bill, Gender: M, Age: 45

Name: Bill, Gender: M, Age: 45
  Permalink  
v10
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 11

This is a submission for the over engineered category. It takes the challenge one step further by:
1. accepting pasted paragraphs of text or manually inputed text;
2. strips text of punctuation and other unwanted characters to split out the words;
3. finds the duplicates;
4. then to give the user feedback, works back through the text, using word recognition, applies colour-coded highlighting to both the text and the repeated words List.

Colour-coding helps the user quickly visualise. Here is a screenshot[^] to demonstrate this. All this is done in real time as the text changes.

Normally I would do this as a MVVM project, however, to keep it tight for this challenge, I've kept it all in the code-behind.

It is using the RepeatedWords extension method from my Solution 4.

Here is the code behind:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
 
namespace WpfFindRepeats
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            highlightColors = (typeof(Colors)).GetPropertyBag()
                .Where(x => 
                {
                    var c = (Color)x.Value; return (c.R > 0x50 && c.R < 0xEF) && 
                                                   (c.G > 0x50 && c.G < 0xEF) && 
                                                   (c.B > 0x50 && c.B < 0xEF);
                })
                .Select(x => (Color)x.Value)
                .OrderBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.R)
                .ToList();
            InitializeComponent();
            DataContext = this;
        }
 
        private Brush highlightForeground 
            = new SolidColorBrush(SystemColors.ControlTextColor);
        private List<Color> highlightColors;
 
        private string userText;
        public string UserText
        {
            get { return userText; }
            set
            {
                ProcessText(value);
                PropertyChanged?.Invoke(this, 
                    new PropertyChangedEventArgs(nameof(UserText)));
            }
        }
 
        private int matchCount;
        public int MatchCount
        {
            get { return matchCount; }
            set
            {
                matchCount = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(MatchCount)));
            }
        }
 
        private int repeatedCount;
        public int RepeatedCount
        {
            get { return repeatedCount; }
            set
            {
                repeatedCount = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(RepeatedCount)));
            }
        }
 
        private void ProcessText(string text)
        {
            MatchCount = 0;
            if (text == userText) return;
            if (string.IsNullOrEmpty(text))
            {
                FormattedText.Inlines.Clear();
                return;
            }
 
            userText = text;
 
            var repeats = text.StripPuncuation().StripCarriageReturn(" ").ToLower()
                              .Split(new[] { ' ' }, 
                                     StringSplitOptions.RemoveEmptyEntries)
                              .GetRepeats().OrderByDescending(x => x).ToList();
 
            if (repeats != null)
            {
                RepeatedCount = repeats.Count;
                var repeatedWords = "[ " +
                    string.Join(", ", repeats.OrderBy(x => x)) + " ]";
 
                Highlight(repeatedWords, repeats,
                    repeatedWords.FindMatches(repeats), RepeatedWords);
                MatchCount = Highlight(text, repeats,
                    text.FindMatches(repeats), FormattedText);
            }
        }
 
        private int Highlight
            (string text, List<string> repeats, 
             IEnumerable<Tuple<int, int, int>> matches, TextBlock textControl)
        {
            int ndx = 0, c = 0;
            textControl.Inlines.Clear();
            foreach (var match in text.NextMatchOf(repeats.ToList(), matches))
            {
                if(match.Item2 > ndx)
                    textControl.Inlines
                               .Add(GetRunForText(text.Substring(ndx, 
                                   match.Item2 - ndx), false, -1));
                textControl.Inlines
                           .Add(GetRunForText(text.Substring(match.Item2, 
                                match.Item3 - match.Item2), true, match.Item1));
                ndx = match.Item3;
                c++;
            }
            if (ndx < text.Length)
                textControl.Inlines
                           .Add(GetRunForText(text.Substring(ndx),
                                false, -1));
            return c;
        }
 
        private Run GetRunForText(string text, bool isHighlighted, int indexColor)
            => new Run(text)
            {
                Foreground = isHighlighted ? highlightForeground : Foreground,
                Background = isHighlighted
                    ? new SolidColorBrush(highlightColors[indexColor 
                                                         % highlightColors.Count])
                    : Background
            };
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            UserText = @"Coding challenge: find the repeated items in a collection of elements.
 
Today's coding challenge is pretty loose in terms of how you approach it and how you interpret the problem.
 
Given a collection of items (integers, strings, objects - whatever) determine the set of subitems in that collection that are repeated.
 
For example
{1,2,3,3,4,5,5,6} => {3,5}
 
Points are awarded for elegance, speed, and excessive use of complicated logic. Over engineering the solution will gain you favours.
 
Last week's winner was Peter Leow, mainly because Graeme_Grant is killing it and I wanted to award a new player. Graeme's Delphi solution brought a tear to my eye. Peter: contact Sean for a trinket.";
        }
    }
    public static class HelperExtension
    {
        public static IEnumerable<T> GetRepeats<T>(this IList<T> items)
            => items?.Intersect(
                   items.Where(x => items.Where(y => Equals(x, y)).Count() > 1));
 
        public static IEnumerable<Tuple<int, int, int>> NextMatchOf
            (this string text, List<string> words, 
             IEnumerable<Tuple<int, int, int>> matches)
        {
            int f = -1;
            foreach (var match in matches.OrderBy(x => x.Item2)
                                         .ThenByDescending(x => x.Item3 - x.Item2))
            {
                if (match.Item2 > f && text.IsWord(words[match.Item1], match.Item2))
                {
                    yield return match;
                    f = match.Item3;
                }
            }
        }
 
        public static IEnumerable<Tuple<int, int, int>> FindMatches
            (this string text, IEnumerable<string> repeats)
        {
            int e, f, p, l = e = f = p = 0;
            foreach (var key in repeats)
            {
                l = key.Length; e = f = 0;
                for (;;)
                {
                    f = text.IndexOf(key, e, 
                                     StringComparison.InvariantCultureIgnoreCase);
                    if (f == -1) break;
                    e = f + l;
                    yield return new Tuple<int, int, int>(p, f, e);
                }
                p++;
            }
        }
 
        public static string StripPuncuation(this string input)
        {
            var sb = new StringBuilder();
            foreach (var c in input)
                sb.Append(char.IsPunctuation(c) ? ' ' : c);
            return sb.ToString();
        }
 
        public static string StripCarriageReturn(this string text,
                                                 string replaceWith = "")
            => !string.IsNullOrEmpty(text)
                ? text.Replace(oldValue: "\r\n", newValue: replaceWith)
                      .Replace(oldValue: "\r", newValue: replaceWith)
                      .Replace(oldValue: "\n", newValue: replaceWith)
                : text;
 
        public static bool IsWord(this string text, string key, int index)
        {
            bool b = true;
            if (index > 0)
            {
                var ptr = index - 1;
                b = IsWordBoundaryChar(text[ptr]);
            }
            var c = index + key.Length;
            return (c < text.Length ? IsWordBoundaryChar(text[c]) : true) && b;
        }
 
        public static bool IsWordBoundaryChar(this char c)
            => char.IsPunctuation(c) || c == ' ' || c == '\r' || c == '\n';
 
        public static Dictionary<string, object> GetPropertyBag(this Type t)
        {
            const BindingFlags flags
                = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
 
            var map = new Dictionary<string, object>();
            foreach (var prop in t.GetProperties(flags))
                map[prop.Name] = prop.GetValue(null, null);
            return map;
        }
    }
}
And Here is the Xaml page:
<Window 
    x:Class="WpfFindRepeats.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfFindRepeats"
    mc:Ignorable="d" WindowStartupLocation="CenterScreen"
    Loaded="Window_Loaded" Height="600" Width="800"
    Title="Code Project Weekly Challenge: Find Repeats">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Find Repeated Items in a Collection of Elements"
                   HorizontalAlignment="Center"
                   FontSize="16" Grid.ColumnSpan="2" Margin="0 10"/>
        <TextBlock Text="Input:" Grid.Row="1" VerticalAlignment="Top" Margin="10"/>
        <TextBox x:Name="UserInput"
                 ScrollViewer.VerticalScrollBarVisibility="Auto"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                 TextWrapping="Wrap"
                 Text="{Binding UserText, Delay=200, 
                                UpdateSourceTrigger=PropertyChanged}"
                 Grid.Row="1" Grid.Column="1" Margin="10" 
                 VerticalAlignment="Stretch" AcceptsReturn="True"/>
        <TextBlock Text="Output:" Grid.Row="2" VerticalAlignment="Top" Margin="10"/>
        <Border Grid.Row="2" Grid.Column="1" Margin="10"
                BorderThickness="{Binding ElementName=UserInput, 
                                          Path=BorderThickness}"
                BorderBrush="{Binding ElementName=UserInput, Path=BorderBrush}">
 
            <ScrollViewer Padding="4" HorizontalScrollBarVisibility="Disabled"
                          VerticalScrollBarVisibility="Auto">
                <TextBlock x:Name="FormattedText" TextWrapping="Wrap"/>
            </ScrollViewer>
        </Border>
        <TextBlock Text="Repeated Words:" Grid.Row="3" Margin="10"/>
        <StackPanel Grid.Row="3" Grid.Column="1" Margin="10">
            <ScrollViewer MaxHeight="70" Padding="4" 
                          HorizontalScrollBarVisibility="Disabled"
                          VerticalScrollBarVisibility="Auto">
                <TextBlock x:Name="RepeatedWords" TextWrapping="Wrap"/>
            </ScrollViewer>
            <TextBlock Margin="0 10 0 0">
                <Run FontWeight="Bold" Text="Keys:"/>
                <Run Text="{Binding RepeatedCount}"/>
                <Run FontWeight="Bold" Text="... Total Matches:"/>
                <Run Text="{Binding MatchCount}"/>
            </TextBlock>
        </StackPanel>
    </Grid>
</Window>
You can download the project[^] and try it out for yourself.

Update: I found some time to refactor this WPF solution into a MVVM solution. I will only highlight key parts but you can download the project[^] and try it.

1. Code Project Extension
using System.Collections.Generic;
using System.Linq;
 
namespace WpfFindRepeats.Mvvm.Extensions
{
    public static class CodeProjectExtension
    {
        public static IEnumerable<T> GetRepeats<T>(this IList<T> items)
            => items?.Intersect(
                   items.Where(x => items.Where(y => Equals(x, y)).Count() > 1));
    }
}
2. MainViewModel
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Media;
using WpfFindRepeats.Mvvm.Extensions;
 
namespace WpfFindRepeats.Mvvm.ViewModels
{
    class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel()
        {
            HighlightColors = (typeof(Colors)).GetPropertyBag()
                .Where(x =>
                {
                    var c = (Color)x.Value; return (c.R > 0x50 && c.R < 0xEF) &&
                                                   (c.G > 0x50 && c.G < 0xEF) &&
                                                   (c.B > 0x50 && c.B < 0xEF);
                })
                .Select(x => (Color)x.Value)
                .OrderBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.R)
                .ToList();
        }
 
        public List<Color> HighlightColors { get; set; }
 
        private string userText;
        public string UserText
        {
            get { return userText; }
            set
            {
                ProcessText(value);
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(UserText)));
            }
        }
 
        private int matchCount;
        public int MatchCount
        {
            get { return matchCount; }
            set
            {
                matchCount = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(MatchCount)));
            }
        }
 
        private int repeatedCount;
        public int RepeatedCount
        {
            get { return repeatedCount; }
            set
            {
                repeatedCount = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(RepeatedCount)));
            }
        }
 
        private string repeatedWords;
        public string RepeatedWords
        {
            get { return repeatedWords; }
            set
            {
                if (repeatedWords != value)
                {
                    repeatedWords = value;
                    PropertyChanged?.Invoke(this,
                        new PropertyChangedEventArgs(nameof(RepeatedWords)));
                }
            }
        }
 
        public ObservableCollection<string> Repeats { get; set; } = 
            new ObservableCollection<string>();
 
        private void ProcessText(string text)
        {
            if (text == userText) return;
            if (string.IsNullOrEmpty(text))
                return;
 
            userText = text;
 
            Repeats.Clear();
            Repeats.AddRange(
                text.StripPuncuation().StripCarriageReturn(" ").ToLower()
                    .Split(new[] { ' ' },
                                     StringSplitOptions.RemoveEmptyEntries)
                    .GetRepeats().OrderByDescending(x => x).ToList());
 
            if (Repeats != null)
            {
                RepeatedCount = Repeats.Count;
                RepeatedWords = "[ " +
                    string.Join(", ", Repeats.OrderBy(x => x)) + " ]";
            }
        }
 
        public void InitText()
        {
            UserText = @"Coding challenge: find the repeated items in a collection of elements.
 
Today's coding challenge is pretty loose in terms of how you approach it and how you interpret the problem.
 
Given a collection of items (integers, strings, objects - whatever) determine the set of subitems in that collection that are repeated.
 
For example
{1,2,3,3,4,5,5,6} => {3,5}
 
Points are awarded for elegance, speed, and excessive use of complicated logic. Over engineering the solution will gain you favours.
 
Last week's winner was Peter Leow, mainly because Graeme_Grant is killing it and I wanted to award a new player. Graeme's Delphi solution brought a tear to my eye. Peter: contact Sean for a trinket.";
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
    }
}
3. HighlightingTextBlock control:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
 
namespace WpfFindRepeats.Mvvm.Controls
{
    [TemplatePart(Name = HighlightTextBlockName, Type = typeof(TextBlock))]
    public class HighlightingTextBlock : Control
    {
        private const string HighlightTextBlockName = "PART_HighlightTextblock";
 
        public static readonly DependencyProperty MatchCountProperty =
            DependencyProperty.Register("MatchCount", typeof(int), typeof(HighlightingTextBlock),
                new PropertyMetadata(0, null));
 
        public static readonly DependencyProperty HighlightSourceProperty =
            DependencyProperty.Register("HighlightSource", typeof(ObservableCollection<string>), typeof(HighlightingTextBlock),
                new PropertyMetadata(null, OnHighlightSourcePropertyChanged));
 
        public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner(
            typeof(HighlightingTextBlock),
            new PropertyMetadata(string.Empty, OnTextPropertyChanged));
 
        public static readonly DependencyProperty TextWrappingProperty = TextBlock.TextWrappingProperty.AddOwner(
            typeof(HighlightingTextBlock),
            new PropertyMetadata(TextWrapping.NoWrap));
 
        public static readonly DependencyProperty TextTrimmingProperty = TextBlock.TextTrimmingProperty.AddOwner(
            typeof(HighlightingTextBlock),
            new PropertyMetadata(TextTrimming.None));
 
        public static readonly DependencyProperty HighlightForegroundProperty =
            DependencyProperty.Register("HighlightForeground", typeof(Brush),
                typeof(HighlightingTextBlock),
                new PropertyMetadata(Brushes.Black));
 
        public static readonly DependencyProperty HighlightColorsProperty =
            DependencyProperty.Register("HighlightColors", typeof(List<Color>),
                typeof(HighlightingTextBlock),
                new PropertyMetadata(new List<Color> { Colors.Yellow }));
 
        private TextBlock highlightTextBlock;
 
        static HighlightingTextBlock()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(HighlightingTextBlock),
                new FrameworkPropertyMetadata(typeof(HighlightingTextBlock)));
        }
 
        public int MatchCount
        {
            get { return (int)GetValue(MatchCountProperty); }
            set { SetValue(MatchCountProperty, value); }
        }
 
        public List<Color> HighlightColors
        {
            get { return (List<Color>)GetValue(HighlightColorsProperty); }
            set { SetValue(HighlightColorsProperty, value); }
        }
 
        public Brush HighlightForeground
        {
            get { return (Brush)GetValue(HighlightForegroundProperty); }
            set { SetValue(HighlightForegroundProperty, value); }
        }
 
        public ObservableCollection<string> HighlightSource
        {
            get { return (ObservableCollection<string>)GetValue(HighlightSourceProperty); }
            set { SetValue(HighlightSourceProperty, value); }
        }
 
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
 
        public TextWrapping TextWrapping
        {
            get { return (TextWrapping)GetValue(TextWrappingProperty); }
            set { SetValue(TextWrappingProperty, value); }
        }
 
        public TextTrimming TextTrimming
        {
            get { return (TextTrimming)GetValue(TextTrimmingProperty); }
            set { SetValue(TextTrimmingProperty, value); }
        }
 
        private static void OnHighlightSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var textblock = (HighlightingTextBlock)d;
            textblock.ProcessTextChanged(textblock.Text, e.NewValue as ObservableCollection<string>);
        }
 
        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var textblock = (HighlightingTextBlock)d;
            textblock.ProcessTextChanged(e.NewValue as string, textblock.HighlightSource);
        }
 
        private void ProcessTextChanged(string text, ObservableCollection<string> repeats)
        {
            if (highlightTextBlock == null)
                return;
 
            highlightTextBlock.Inlines.Clear();
            MatchCount = 0;
 
            if (highlightTextBlock == null || string.IsNullOrWhiteSpace(text))
                return;
 
            if (repeats == null || repeats.Count == 0)
            {
                highlightTextBlock.Inlines.Add(new Run(text));
                return;
            }
 
            int ndx = 0, c = 0;
            foreach (var match in text.NextMatchOf(repeats, text.FindMatches(repeats)))
            {
                if (match.Item2 > ndx)
                    highlightTextBlock.Inlines
                               .Add(GetRunForText(text.Substring(ndx,
                                   match.Item2 - ndx), false, -1));
                highlightTextBlock.Inlines
                           .Add(GetRunForText(text.Substring(match.Item2,
                                match.Item3 - match.Item2), true, match.Item1));
                ndx = match.Item3;
                c++;
            }
            if (ndx < text.Length)
                highlightTextBlock.Inlines
                           .Add(GetRunForText(text.Substring(ndx),
                                false, -1));
            MatchCount = c;
        }
 
        private Run GetRunForText(string text, bool isHighlighted, int indexColor)
           => new Run(text)
           {
               Foreground = isHighlighted ? HighlightForeground : Foreground,
               Background = isHighlighted
                   ? new SolidColorBrush(HighlightColors[indexColor
                                                    % HighlightColors.Count])
                   : Background
           };
 
        public override void OnApplyTemplate()
        {
            highlightTextBlock = GetTemplateChild(HighlightTextBlockName) as TextBlock;
            if (highlightTextBlock == null) return;
            ProcessTextChanged(Text, HighlightSource);
        }
    }
}
4. The HighlightingTextBlock control DefaultTemplate:
<ResourceDictionary 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:c="clr-namespace:WpfFindRepeats.Mvvm.Controls">
  <Style TargetType="{x:Type c:HighlightingTextBlock}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type c:HighlightingTextBlock}">
          <Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
              VerticalAlignment="{TemplateBinding VerticalAlignment}">
            <TextBlock x:Name="PART_HighlightTextblock"
                   FontWeight="{TemplateBinding FontWeight}"
                   FontSize="{TemplateBinding FontSize}"
                   FontFamily="{TemplateBinding FontFamily}"
                   FontStretch="{TemplateBinding FontStretch}"
                   FontStyle="{TemplateBinding FontStyle}"
                   Margin="{TemplateBinding Margin}"
                   Padding="{TemplateBinding Padding}"
                   TextWrapping="{TemplateBinding TextWrapping}"
                   TextTrimming="{TemplateBinding TextTrimming}" />
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>
5. And Here is the Xaml page (no code-behind):
<Window 
    x:Class="WpfFindRepeats.Mvvm.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:WpfFindRepeats.Mvvm.ViewModels"
    xmlns:ex="clr-namespace:WpfFindRepeats.Mvvm.Extensions"
    xmlns:c="clr-namespace:WpfFindRepeats.Mvvm.Controls"
    mc:Ignorable="d" WindowStartupLocation="CenterScreen" 
    Height="600" Width="800" Loaded="{ex:MethodBinding InitText}"
    Title="Code Project Weekly Challenge: Find Repeats">
    <Window.DataContext>
        <vm:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Find Repeated Items in a Collection of Elements"
                   HorizontalAlignment="Center"
                   FontSize="16" Grid.ColumnSpan="2" Margin="0 10"/>
        <TextBlock Text="Input:" Grid.Row="1" VerticalAlignment="Top" Margin="10"/>
        <TextBox x:Name="UserInput"
                 ScrollViewer.VerticalScrollBarVisibility="Auto"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                 TextWrapping="Wrap"
                 Text="{Binding UserText, Delay=200, 
                                UpdateSourceTrigger=PropertyChanged}"
                 Grid.Row="1" Grid.Column="1" Margin="10" 
                 VerticalAlignment="Stretch" AcceptsReturn="True"/>
        <TextBlock Text="Output:" Grid.Row="2" VerticalAlignment="Top" Margin="10"/>
        <Border Grid.Row="2" Grid.Column="1" Margin="10"
                BorderThickness="{Binding ElementName=UserInput, 
                                          Path=BorderThickness}"
                BorderBrush="{Binding ElementName=UserInput, Path=BorderBrush}">
 
            <ScrollViewer Padding="4" HorizontalScrollBarVisibility="Disabled"
                          VerticalScrollBarVisibility="Auto">
                <c:HighlightingTextBlock x:Name="OutText"
                                    Text="{Binding UserText}"
                                    HighlightSource="{Binding Repeats}"
                                    TextWrapping="Wrap"
                                    HighlightForeground="Black"
                                    HighlightColors="{Binding HighlightColors}"
                                    MatchCount="{Binding MatchCount, Mode=TwoWay}"/>
            </ScrollViewer>
        </Border>
        <TextBlock Text="Repeated Words:" Grid.Row="3" Margin="10"/>
        <StackPanel Grid.Row="3" Grid.Column="1" Margin="10">
            <ScrollViewer MaxHeight="70" Padding="4" 
                          HorizontalScrollBarVisibility="Disabled"
                          VerticalScrollBarVisibility="Auto">
                <c:HighlightingTextBlock Text="{Binding RepeatedWords}" 
                                    HighlightSource="{Binding Repeats}"
                                    TextWrapping="Wrap"
                                    HighlightForeground="Black"
                                    HighlightColors="{Binding HighlightColors}"/>
            </ScrollViewer>
            <TextBlock Margin="0 10 0 0">
                <Run FontWeight="Bold" Text="Keys:"/>
                <Run Text="{Binding RepeatedCount}"/>
                <Run FontWeight="Bold" Text="... Total Matches:"/>
                <Run Text="{Binding MatchCount}"/>
            </TextBlock>
        </StackPanel>
    </Grid>
</Window>
  Permalink  
v10
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 12

Here is a nostalgic trip... a Batch file solution!
@echo off
setlocal enabledelayedexpansion
set c=0
for %%x in (%*) do (
    set /a c+=1
    set o=!o! %%x
    set p[!c!]=%%x
)
set i=1
set k=0
:a1
    set /a j=i
:a2
    if %i%==%j% goto a3
    if !p[%i%]!==!p[%j%]! goto a4
:a3
    set /a j+=1
    if %j% leq %c% goto a2
    set /a i+=1
    if %i% leq %c% goto a1
    goto a7
:a4
    if %k%==0 (
        set k=1
        set r[!k!]=!p[%i%]!
        goto a3
    )
    set l=1
:a5
    if !p[%i%]!==!r[%l%]! goto a3
    set /a l+=1
    if %l% gtr %k% goto a6
    goto a5
:a6
    set /a k+=1
    set r[!k!]=!p[%i%]!
    goto a3
:a7
    set i=1
:a8
    if %k%==0 goto a9
    set a=!a! !r[%i%]!
    set /a i+=1
    if %i% leq %k% goto a8
:a9
    echo For [%o% ]
    if %i%==1 goto aa
    echo  ^> has [%a% ] elements repeated
    goto ab
:aa
    echo  ^> There are no repeats
:ab
And the execution & output with test parameters:
C:\Code Project\Weekly Challenge>findrepeats
For [ ]
 > There are no repeats
 
C:\Code Project\Weekly Challenge>findrepeats 1 2 3 3 4 5 5 6
For [ 1 2 3 3 4 5 5 6 ]
 > has [ 3 5 ] elements repeated
 
C:\Code Project\Weekly Challenge>findrepeats 1 2 3 2 4 2 5 2 6 5 2 6 8
For [ 1 2 3 2 4 2 5 2 6 5 2 6 8 ]
 > has [ 2 5 6 ] elements repeated
 
C:\Code Project\Weekly Challenge>findrepeats apples oranges mangos apples peaches pineapples mangos
For [ apples oranges mangos apples peaches pineapples mangos ]
 > has [ apples mangos ] elements repeated
 
C:\Code Project\Weekly Challenge>findrepeats "2016 Mazda CX9" "2014 Ford XR5" "2010 Ford XR5" "2015 Holden Commodore" "2016 Mazda CX9"
For [ "2016 Mazda CX9" "2014 Ford XR5" "2010 Ford XR5" "2015 Holden Commodore" "2016 Mazda CX9" ]
 > has [ "2016 Mazda CX9" ] elements repeated
 
C:\Code Project\Weekly Challenge>findrepeats 1 2 3 3 4 5 5 6 apples oranges mangos apples peaches pineapples mangos "2016 Mazda CX9" "2014 Ford XR5" "2010 Ford XR5" "2015 Holden Commodore" "2016 Mazda CX9"
For [ 1 2 3 3 4 5 5 6 apples oranges mangos apples peaches pineapples mangos "2016 Mazda CX9" "2014 Ford XR5" "2010 Ford XR5" "2015 Holden Commodore" "2016 Mazda CX9" ]
 > has [ 3 5 apples mangos "2016 Mazda CX9" ] elements repeated
  Permalink  
v5
Comments
Jon McKee 14-Feb-17 17:08pm
   
I know there's an implicit ENDLOCAL at the end of a batch script but it still bugs me :P Hehe, anyways, good job on... 4 solutions across 5 languages? Wow x_x
Graeme_Grant 14-Feb-17 20:56pm
   
Thanks Jon. :)

Yeah, this Batch Script one started as a curiosity...

You could include XAML as another language ;)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


Advertise | Privacy |
Web03 | 2.8.170924.2 | Last Updated 18 Feb 2017
Copyright © CodeProject, 1999-2017
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100