首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >寻找重复

寻找重复
EN

Code Review用户
提问于 2017-02-06 23:50:47
回答 2查看 1K关注 0票数 2

我决定在C#中做更多的工作,编写两种查找重复的方法,一种是简单的方法,另一种是利用C#的LINQ功能作为一种学习和培训形式。下面是我的代码,如果有更简洁的方法,我会很感激你对它的风格,设计,如果有更简洁的方法的批评。

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Practice
{
    #region FindDuplicate
    class FindDuplicate
    {
        private int[] input;
        private List<int> dupList;
        private IEnumerable<int> dupes;

        public FindDuplicate(int[] input)
        {
            this.input = input;
        }


        /**
         * This is a more advanced version of printing out the duplicates in the sense that we are using
         * SQL-Like statements in the form of Group, where, and select. If these were SQL it may look like:
         * SELECT * FROM INPUT s1
         * JOIN INPUT s2
         * ON s2.value = s1.value 
        */
        public FindDuplicate finderVariantTwo()
        {
            //Note how we do not need to sort the array, the grouping will do it for us.
            this.dupes = this.input.GroupBy(result => result)
                .Where(whereValueClause => whereValueClause.Count() > 1)
                .Select(indexValue => indexValue.Key);

            return this;
        }

        /**
         * This is the "naive" variant, and the one that first came to my mind. The idea here is simple: 
         * First, 
         */
        public FindDuplicate getDuplicates()
        {
            this.dupList = new List<int>();

            //for this, let us first sort the array to make it easier for the loop. 
            Array.Sort(this.input);

            for(int i = 0; i < input.Length; i++)
            {
                //this is to make sure we do not have an index out of bounds.
                int next = (i < input.Length-1) ? i+1 : input.Length - 1;

                if(input[i] == input[next] && !dupList.Contains(input[i]))
                {
                    dupList.Add(input[i]);
                }
            }

            return this;
        }


        public void getDuplicatesTwo()
        {
            String result = "Result => {";
            foreach (int i in this.dupes)
            {
                result += i + ",";
            }
            result += "}";
            Console.WriteLine(result);
        }

        public void printResultVariantOne()
        {
            String result = "Result => {";
            foreach(int i in this.dupList)
            {
                result += i + ",";
            }
            result += "}";
            Console.WriteLine(result);
        }
        #endregion
    }

    class TestFindDuplicates
    {
        static void Main(string[] args)
        {
            int[] input = { 2, 3, 2, 4, 5, 5, 1, 10, 3, 10, 9, 9 };

            FindDuplicate find = new FindDuplicate(input);

            find.getDuplicates().printResultVariantOne();

            Console.WriteLine("\n");

            find.getDuplicatesTwo().printResultVariantTwo();

            //to stop the window from closing as soon as it finishes running
            Console.ReadKey();
        }
    }
}

但有一件事我确实想知道,我知道这不是问题/答案的一面,所以我很抱歉。但是,是否有可能以某种方式将我的输入转换为泛型呢?我试着环顾网络,但没有一个答案是足够的。也就是说,我是否可以说输入是T类型的,而不是硬编码的int值?

EN

回答 2

Code Review用户

回答已采纳

发布于 2017-02-07 08:47:39

改进

类FindDuplicate

类名应该是名词,例如DuplicateFinder

公众FindDuplicate finderVariantTwo() public FindDuplicate getDuplicates()

这不是一个用户友好的API。首先需要创建FindDuplicate类的实例,然后可以搜索副本。这些方法可以返回结果。

如果您想要实现多个搜索重复项的算法,您应该查看一下战略模式

This.input.GroupBy(结果=> result) .Where(whereValueClause => whereValueClause.Count() > 1) .Select(indexValue => indexValue.Key);

长而冗长的名字是一件好事,但在这里却不是。result是什么?whereValueClauseindexValue是什么?它们更令人困惑,而不是有用。

如果没有更好的名称,则泛型项目大多类似于x,例如其类型名称的首字母(S)。

Where中,您使用一个组,这样字母g就可以了。同样的情况也适用于Select,您可以在其中使用组agian。

考虑到这一点:

代码语言:javascript
运行
复制
input
    .GroupBy(x => x)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);

#区域FindDuplicate

区域主要是品味的问题。我不喜欢它们,因为你有更小的+来膨胀/崩溃。我发现如果您开始使用区域,那么您的类/方法/循环等就太大了,您应该开始考虑重构它。有些人使用它们来分组类似的方法,甚至字段/属性。我建议在有一个很好的理由(通常没有,并且需要一个新的类/文件/命名空间)的情况下,尽量少地使用它们。

(我不知道这个部分会让我输多少票)。

泛型搜索

你问

但是,是否有可能以某种方式将我的输入转换为泛型呢?

是的。您需要使该方法成为通用的,这意味着应该接受任何集合IEnumerable<T>和实现IEqualityComparer<T>接口的比较器,这样它就可以判断两个项是否相同。

以下是一个例子。

第一个使用GroupBy

代码语言:javascript
运行
复制
public static IEnumerable<T> FindDuplicates<T>(this IEnumerable<T> values, IEqualityComparer<T> comparer)
{
    return 
        values
        .GroupBy(x => x, comparer)
        .Where(g => g.Count() > 1)
        .Select(g => g.Key);
}

比较器

对于简单的情况,可以使用默认的比较器,如

代码语言:javascript
运行
复制
EqualityComparer<T>.Default

对于更复杂的类型,如Person

代码语言:javascript
运行
复制
class Person 
{ 
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

您将编写一个实现IEqualityComparer<T>接口的类:

代码语言:javascript
运行
复制
class PersonComparer : IEqualityComparer<Person>
{ 
    public bool Equals(Person x, Person y)
    {
        return x.FirstName == y.FirstName && x.LastName == y.LastName;
    }

    public int GetHashCode(Person obj)
    {
        return $"{obj.LastName}, {obj.FirstName}".GetHashCode();
    }
}

这实际上只是一个非常简单的示例,演示了需要实现的两种方法。您可能希望使名称比较大小写不敏感,或修剪名称或计算不同的哈希代码。做这件事有很多方法,但现在你知道如何开始了。

C# 7

使用C# 7,您可以通过字典很好地实现它:

代码语言:javascript
运行
复制
public static IEnumerable<T> FindDuplicates<T>(this IEnumerable<T> values, IEqualityComparer<T> comparer)
{
    var dictionary = new Dictionary<T, int>(comparer);
    foreach (var value in values)
    {
        dictionary[value] = dictionary.TryGetValue(value, out int counter) ? ++counter : 0;
    }
    return dictionary.Where(x => x.Value > 1).Select(x => x.Key);
}
票数 2
EN

Code Review用户

发布于 2017-02-07 00:49:02

我不会为此使用类,它更像是一种扩展方法。LINQ版本看起来不错,您可以将它变成如下所示的扩展方法:

代码语言:javascript
运行
复制
public static T[] FindDuplicates<T>(this IEnumerable<T> source)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }
    return source.GroupBy(result => result)
        .Where(whereValueClause => whereValueClause.Count() > 1)
        .Select(indexValue => indexValue.Key).ToArray();
}

注意,这里有一个null检查,因为这是一个扩展方法,我们需要确保它对任何使用它的人都能正常工作,当然,如果出现这种情况,也会处理异常。

在您的类中有一些东西可以改进,但是您应该使用这个单一的方法,这会使您的类变得多余,我将不再讨论它。

如果你想在总体上改进的话,给出一个简单的想法:

  • 命名
  • StringBuilderstring级联
  • 奇怪的返回类型
  • 一些不必要的评论
  • 地域

有句话吸引了我的眼球:

注意,我们不需要对数组进行排序,分组将为我们完成这一任务。

分组并不意味着排序。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/154645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档