Chris Maunder Ответов: 13

Задача кодирования: найти повторяющиеся элементы в коллекции элементов.


Сегодняшняя задача кодирования довольно свободна с точки зрения того, как вы подходите к ней и как вы интерпретируете проблему.

Учитывая набор элементов (целые числа, строки, объекты - все, что угодно), определите набор элементов в этой коллекции, которые повторяются.

Например
{1,2,3,3,4,5,5,6} => {3,5}


Очки начисляются за элегантность, скорость и чрезмерное использование сложной логики. Над проектированием решение приобретет вам благосклонность.

Победитель прошлой недели был Питер Леоу, главным образом потому, что Graeme_Grant убивает его, и я хотел наградить нового игрока. Дельфи-решение Грэма вызвало у меня слезы на глазах. Питер: свяжись с Шоном за безделушкой.

Graeme_Grant

Наверное, это был своего рода комплимент ... Мне понравилось изучать новый ретро-язык... что-то вроде заставляет меня пожалеть, что я не провел с ним больше времени раньше... На прошлой неделе это был первый раз, когда я был там, и больше никто не участвовал ... на самом деле немного облом...

Maciej Los

Крис,
Не могли бы вы рассказать мне о самой важной идее кодирования Challenge? До сих пор я был уверен, что самое главное-обеспечить одно нетрадиционное решение, но теперь я вижу, что кодирование chalenge было изменено на "сколько языков программирования вы знаете?". Я бы предложил опубликовать правила кодирования Challenge. Если метод решения проблемы один и тот же (одна и та же идея), то количество решений не может быть причиной славы (upvotes).
Примечание: Я не вижу ничего плохого в шести или более решениях Graeme_Grant: F#, Linq и non-Linq версии C# и VB.NET, PowerShell, BatchScript, WPF(?!?), но... это воняет хвастовством.

Chris Maunder

-теперь я вижу, что кодирование chalenge было изменено на "сколько языков программирования вы знаете?".
Нет, дело совсем не в этом. Один ответ-это все, что я после. Единственный самый *интересный* ответ. Тот, который вызывает больше всего споров, больше всего похвал, больше всего удовольствия. Тот, который показывает, что кто-то растянулся немного больше, чем другие. Вот в чем дело.

Graeme_Grant

Это дало мне возможность изучить 3 новых языка (F#, Powershell, Free Pascal), где я обычно не беспокоился бы. Это было интересное и веселое путешествие.

VB-это то, откуда я пришел. Так же как и для C#/VB, не все программы на C#. Когда у меня есть время, я прикрепляю версию VB для тех, кто этого не делает.

Спасибо Крису за то, что он это сделал! :)

Maciej Los

Крис, спасибо за объяснение.

Грэм, прости меня, если я обидел тебя. Это не входило в мои намерения. Я начал свое путешествие по программированию с Pascal и VBA. У меня есть средний опыт работы с C++. Теперь я использую VB.NET и C# (предпочтительно). Как вы можете видеть, я мог бы предложить 5 решений, но идея решения проблемы была бы той же самой. Поэтому я предпочел бы предложить одно решение (на любом языке). Это моя точка зрения.

Овации,
Мацей

Graeme_Grant

Было бы здорово, если бы вы приняли участие в этих испытаниях. Есть еще один новый сейчас активен[^]...

Maciej Los

Я был там ;)

Graeme_Grant

Да... 1 из 11 задач... А как насчет нынешнего?

Maciej Los

Моя философская натура говорит: Должен ли я участвовать в соревнованиях?
:смеяться:

[no name]

Было бы одно решение на каждого члена достойным ограничением.

Graeme_Grant

Я всегда ожидаю, что только мое первое решение будет оценено.

13 Ответов

Рейтинг:
2

User 59241

Вот один из них, использующий c++, шаблоны и stl sort(). Для не встроенных типов оператор< перегружается для включения сортировки, а оператор== перегружается для сравнения. Класс человек позволяет изменять сам класс для переопределений. Если это невозможно, используются внешние переопределения, и компилятор выбирает правильный вариант. Это показано с помощью класса ЧЕЛОВЕК

#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;
}


Выход:
Int: 3
Int: 5

Инт: 2
Int: 3
Int: 5
Инт: 7

Двойной: 2.2
Двойной: 2.6
Дубль: 3
Двойной: 3,3
Двойной: 5
Двухместный: 7

Строка: test1

Имя: Билл, Пол: М, Возраст: 45 Лет

Имя: Билл, Пол: М, Возраст: 45 Лет


Рейтинг:
2

#realJSOP

Я знаю , что это поздно:), но я придумал это вчера. Я думаю, что он не так сильно спроектирован, как нам бы хотелось, но эй, он выполняет это требование.

// this code block identifies the dupes
int[] ints = new int[] { 1, 2, 3, 3, 4, 5, 5, 6 };
HashSet<int> notdupes = new HashSet<int>();
HashSet<int> dupes    = new HashSet<int>();
foreach (int i in ints)
{
    if (!notdupes.Add(i))
    {
        dupes.Add(i);
    }
}
notdupes.RemoveWhere(x => { return dupes.Contains(x); });


// everything past this comment is just to display the results

Console.Write("Non-duplicates are {");
int index = 0;
foreach (int i in notdupes)
{
    Console.Write(string.Format("{0}{1}", i, (index == notdupes.Count - 1) ? "" : ","));
    index++;
}
Console.WriteLine("}");

if (dupes.Count > 0)
{
    Console.Write("Duplicates are {");
    index = 0;
    foreach (int i in dupes)
    {
        Console.Write(string.Format("{0}{1}", i, (index == dupes.Count - 1) ? "" : ","));
        index++;
    }
    Console.WriteLine("}");
}
else
{
    Console.WriteLine("No duplicates found.");
}
Console.ReadKey();


Рейтинг:
1

Graeme_Grant

Вот мое быстрое решение... Сделал тесты для список значений null, элементы списка, включая значения null, используя элементы списка Int, String, и сложный Object (Car).

Обновление: Добавлено преобразование F# в C# и VB.Net-да.

Выбери свой яд... МММ.. язык - Ф#, С#, или VB.Net. Есть также В PowerShell (решение 9) &усилитель; Пакетный сценарий (решение 12) версии ниже. Или, если хотите визуализировать, есть WPF (решение 11) версия, которую вы можете попробовать, и она будет обновлять подсветку в режиме реального времени.


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

Вот полное решение с тестовыми случаями:


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


Richard Deeming

Что делать, если последовательность содержит null?

И сколько раз вы повторяете этот список? :П

Graeme_Grant

Работать отлично. ;) также будет обновляться тестовый код.

Richard Deeming

- Вы уверены? :П

Тестирование в 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

запустите демонстрацию и посмотрите... Первая нулевая проверка items?. остановит появление ошибки, которую вы видите в LinqPad.

Richard Deeming

Но у вас нет демо-версии с null пункт в списке. :)

Graeme_Grant

Прости, но ... .. List<int> empty1Test = null; и var empty2Test = new List<int>();

Richard Deeming

Нет, это "а null список", а не "список с null пункт в нем". :)

Попробуйте это с помощью new List<string> { "A", "A", null };

Graeme_Grant

это не было частью требования...

Richard Deeming

Но это было не так нет это тоже часть требования! :Д

Graeme_Grant

Только для тебя, Ричард, я сделаю небольшое изменение. Счастлива?

Richard Deeming

Так-то лучше. :Д

Graeme_Grant

Хотите также отладить мой код F#? ;)

Graeme_Grant

Хотите также отладить мой код F#? ;)

Richard Deeming

Выглядит хорошо для меня. :Д

Graeme_Grant

Это моя 3-я попытка F# ... не язык выбора! ;)

Graeme_Grant

Я опубликовал версию PowerShell, если вы тоже хотите отладить ее... ;)

Richard Deeming

Подсказка: Попробуйте заменить: y.Equals(x)
с: Equals(y, x)

Рейтинг:
1

Richard Deeming

Здесь, очевидно, по-сложнее, по-проектированный решением c# :

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;
            }
        }
    }
}

Недостатком является то, что он должен хранить в памяти копию каждого отдельного элемента из входной последовательности. С чрезвычайно большой входной последовательностью вы потенциально можете получить OutOfMemoryException.


РЕДАКТИРОВАТЬ: Вариант 2, с помощью Dictionary<T, byte>, как было предложено 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;
                }
            }
        }
    }
}


PIEBALDconsult

Конечно, вы поддерживаете только _references_ к пунктам.
И я ожидаю, что два хэш-набора-это перебор.

Richard Deeming

Для справочных типов-да. Вы все еще можете попасть в исключение "из памяти", если HashSet<T> становится слишком большим.

Richard Deeming

Два хэш-набора было бы было бы излишним, если бы вы не заботились о дубликатах в выходных данных.

Поскольку мы ищем "набор" повторяющихся элементов, это означает, что мы делать уход, и мы хотим, чтобы каждый дублированный элемент появлялся только один раз. :)

PIEBALDconsult

Я нахожу, что словарь работает лучше.

Richard Deeming

Хорошо, я добавил вариацию, используя словарь. Теперь доволен? :)

Chris Maunder

"С чрезвычайно большой входной последовательностью вы потенциально можете получить исключение OutOfMemoryException", - вот в чем заключается проблема. Простой ответ прост. Это когда все становится немного сумасшедшим, что отделяет мужчин от мальчиков.

Maciej Los

Мне кажется, что это хорошо, и ваше решение более универсально, чем другие ;)

Graeme_Grant

Как это более обобщенно? Кроме того, он потерпит неудачу, если есть нулевой элемент ...

An unhandled exception of type 'System.NullReferenceException' occurred

Maciej Los

Короче говоря: из-за использования IEqualityComparer<T>, так что любой тип данных может быть использован.

Graeme_Grant

Это требуется только для сложных объектов/классов. Чего его решение не показывает, так это того, что вам все равно придется переопределить GetHashCode и Equals на каждом объекте класса для его работы - без переопределений, то IEqualityComparer<T> не будет работать.

Я делаю то же самое в Решение 4 Единственная разница, как я продемонстрирую, заключается в том, что я установил его для класса так, чтобы он работал с любым внутренним . Чистая сортировка или механизм сравнения, использующий компаратор по умолчанию. Это все еще позволяет использовать пользовательские компараторы*, если* требуется. Делая это таким образом, я могу использовать классы с В LINQ или List.Sort() как я это делаю в Решение 4.. Вы можете увидеть результаты выборочных тестов, которые я предоставляю в решении.

Единственное, что предлагает это решение, - это введение пользовательского компаратора, но все же имеет те же требования, что и выше. Пользовательская сортировка не является обязательным требованием этой задачи.

Richard Deeming

То IEqualityComparer<T> интерфейс имеет ничего это связано с пользовательской сортировкой. Ты думаешь о том, что ... IComparer<T> интерфейс.

А если вы предоставите заказ IEqualityComparer<T> например, вы не придется переопределить GetHashCode и Equals Вам нужно только переопределить их, если вы используете компаратор равенства по умолчанию.

Graeme_Grant

Я проверил, и это не удалось с POCOs... Я могу опубликовать тест в интернете, если вы хотите.

Richard Deeming

Для меня это прекрасно работает:

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

Я вижу, что это будет работать для простых случаев, но не для более сложных реальных случаев при работе с унаследованными классами. Но для этого вызова он делает свою работу.

Richard Deeming

Почему возникает проблема с наследуемыми классами?

Либо класс определяет свои собственные правила равенства путем переопределения GetHashCode и Equals; или обычай IEqualityComparer<T> обеспечивает правила для равенства.

Работа с наследуемыми классами более сложна в обоих случаях, но не невозможна ни в том, ни в другом. :)

Maciej Los

Ну... вызов был определен как: Учитывая набор элементов (...что угодно), определите набор элементов в этой коллекции, которые повторяются Значит, должен быть какой-то способ сравнивать объекты. IEqualityComparer кажется, это лучший способ для сравнения объекта.

Graeme_Grant

Я не сказал, что сравнение объектов не является частью задачи, я сказал:: "Пользовательская сортировка не является обязательным требованием этой задачи" Но Ричард и я обсуждали его реализацию, как вы уже читали...

Richard Deeming

Первый вариант будет нет сбой, если есть нулевой элемент.

Второй вариант будет, но с Ан ArgumentNullException из словаря, а не из книги. NullReferenceException.

Graeme_Grant

Вы уверены... Я могу опубликовать тест в интернете, если вы хотите.

[редактировать:] Я вижу, что вы просто изменили свой код, чтобы исправить это.

Richard Deeming

Да, я уверена.

var items = new[] { "hello", null, "hello", null, "goodbye" };
items.FindDuplicates().Dump();

Вывод из варианта 1:
{ "hello", null }

Выход из (фиксированного) варианта 2:
{ "hello", null }

Рейтинг:
1

Peter Leow

Последний код дня перед сном:

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))
ознакомьтесь с демо-версией по адресу Задача кодирования: найти повторяющиеся элементы в коллекции элементов, Python 3[^] и выводится следующим образом:
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']

Проснулся с рычащим стомарчем, который напомнил мне скормить None (null в Python) списку, обновил решение и отправился на завтрак.


Рейтинг:
1

Matthew Dennis

Предлог для запуска VS 2017 RC :).

Предполагая, что элементы могут быть сравнены для равенства, то

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);
        }
    }
}

что приводит к

Duplicated items: {1,2,3,3,4,5,5,6} => {3,5}


Richard Deeming

Это в конечном итоге приведет к хранению ссылки на каждый элемент во входной последовательности. Я подозреваю, что ваш ударит по OutOfMemory исключение раньше, чем у меня. :)

Matthew Dennis

Верно, но тогда я бы обрабатывал огромный набор данных и использовал бы что-то немного более сложное, что позволило бы параллельную обработку данных. Возможно, сортировка и сканирование на наличие дубликатов. Это потребовало бы, чтобы предметы были сопоставимы, а также равноценны.

Рейтинг:
1

Graeme_Grant

Я подумал, что попробую PowerShell еще раз - 2-я попытка с этим скриптовым языком. Я все еще новичок в этом, поэтому, пожалуйста, будьте добры...

Вот быстрая чистая нативная версия PowerShell...

function GetRepeats { param ($l)
	$l | group -Property {$_.ToString()} | where-object {$_.count -gt 1} | Foreach {"$($_.name)"}
}
Вот полное решение с тестовыми случаями:
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


И выход:
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


Рейтинг:
1

Graeme_Grant

Это представление для более проектированный категории. Это делает вызов еще на один шаг вперед.:
1. принятие вставленных абзацев текста или введенного вручную текста;
2. Очистите текст от знаков препинания и других нежелательных символов, чтобы разделить слова;
3. находит дубликаты;
4. затем, чтобы дать обратную связь пользователю, работает обратно через текст, используя распознавание слов, применяет цветовое выделение как к тексту, так и к списку повторяющихся слов.

Цветовое кодирование помогает пользователю быстро визуализировать. Вот это да скриншот[^] чтобы продемонстрировать это. Все это делается в режиме реального времени по мере изменения текста.

Обычно я бы сделал это как проект MVVM, однако, чтобы сохранить его плотным для этой задачи, я сохранил все это в коде.

Он использует RepeatedWords метод расширения из моего решения 4.

Вот код, стоящий за этим:

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))
    


Рейтинг:
1

Graeme_Grant

Вот вам ностальгическое путешествие... решение для пакетного файла!

@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
А также выполнение & вывод с тестовыми параметрами:
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


Jon McKee

Я знаю, что в конце пакетного скрипта есть неявный ENDLOCAL, но он все равно меня раздражает :P Хе-Хе, в любом случае, хорошая работа... 4 решения на 5 языках? Вау x_x

Graeme_Grant

Спасибо, Джон. :)

Да, этот пакетный сценарий начинался как курьез...

Вы можете включить XAML в качестве другого языка ;)

Рейтинг:
0

cigwork

Опаздывает на вечеринку, ничего страшного. Ты хочешь перестроиться? Вот и мы. Хит-Робинсон* природа этого "решения" - всего лишь бонус. :Д

*Для американских читателей : Руб Голдберг.

Псевдокод только потому, что жизнь слишком коротка, чтобы на самом деле возиться с этим мусором.

1. Купите сервер.

2. Купить реляционной СУБД, лицензии

3. Установите RDMBS на сервер

4. Создайте БД в RDMBS

5. В вашей БД создайте таблицу:

duplicates (
 testId varchar(xx),
 itemAsString varchar
 constraint PK_makeItCrash primary key (testId, itemAsString)
)


6. напишите код для вставки Строковой версии элемента в таблицу

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);


Конечно, это сообщает о каждой попытке вставки, так что если у вас есть n, где n>2, копии элементов, вы получите n-1 отчетов о дублировании.

Чуть менее Чокнутая, да... ну ... решением было бы сбросить ограничение PK, вставить все элементы, а затем запустить стандартный SQL-запрос, чтобы получить сплющенные дубликаты из таблицы и повторно надуть их.

-- 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 


Рейтинг:
0

Matthew Dennis

Вот улучшенная версия памяти BetterDuplicated- Я сохранил старое . Duplicated метод для сравнения. Новая версия требует, чтобы входные данные были списком, чтобы их можно было отсортировать.

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;
            }
        }
    }
}


Graeme_Grant

Эй, Мэтью, я только что опубликовал обновленную версию своего кода без Linq (как и на прошлой неделе), не проверив сначала, что опубликовали другие. Я только что заметил, что наши решения почти идентичны! Единственная разница заключается в том, что Ваш будет терпеть неудачу, если есть нулевой элемент ...

An unhandled exception of type 'System.NullReferenceException' occurred

Рейтинг:
0

PIEBALDconsult

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 ) ;
}


Graeme_Grant

Может ли он обрабатывать больше, чем ints? Может быть, занятия?

PIEBALDconsult

Так и должно быть. Зависит от того, как определяется тип. Я оставляю всю тяжелую работу на словарь, так что вините Microsoft, если он не работает. :пожимать:

Graeme_Grant

Просто запустите его, и он действительно поддерживает объекты, однако он потерпит неудачу, если есть нулевой элемент ...

An unhandled exception of type 'System.NullReferenceException' occurred
Вот ссылка на сайт тестовый проект[^] (с удаленным нечетным форматированием), который был использован...

PIEBALDconsult

Мне все равно.
Спецификация говорит "коллекция элементов" - нулевой результат _should_ приведет к исключению.

Рейтинг:
0

Kornfeld Eliyahu Peter

<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>