如何从数组中找到第n个副本

时间:2013-11-14 12:36:08

标签: c# arrays

我试图解决这个问题。

基本上我需要从字符数组中选择第二个副本。

Input {'x','y','z','x','y'} output: y
Input { 'a', 'a', 'b', 'a', 'c', 'b', 'a', 'c', 'b' } Output: b
Input { 'a','a','a','b','a','c','b','a','c','b' } output: b

编辑:

Input {'a', 'b', 'c', 'b', 'a', 'c', 'b', 'a', 'c', 'b'} Output: a

我尝试过编写这段代码,但如果第一个字符立即重复,它会失败:(有任何帮助纠正这个问题吗?

 public static char returnSecondDuplicate(char[] arr)
        {
            if (arr.Length == 0)
                throw new ArgumentNullException("empty input");
            var dictionary = new Dictionary<char, int>();
            Char second = '\0';
            int duplicateCount = 0;

            for (int i = 0; i <= arr.Length - 1; i++)
            {

                if (!dictionary.ContainsKey(arr[i]))
                {
                    dictionary.Add(arr[i], 1);
                }
                else
                {
                    duplicateCount++;

                    if (duplicateCount == 2)
                    {
                        second = arr[i];
                    }
                }
            }

            return second;
        }

4 个答案:

答案 0 :(得分:2)

这应该很好地解决它:

var secondDuplicate = input.GroupBy( c => c)
                           .Where( g => g.Count() > 1)
                           .Skip(1)
                           .First()
                           .Key;

首先你将它们分组,然后用只有一个元素折扣所有组(因为它们不是重复的),然后取第二个(通过跳过第一个)

答案 1 :(得分:2)

这是适用于特定情况的通用扩展方法:

public static T GetNthDuplicate<T>(this IEnumerable<T> source, int n)
{
    HashSet<T> hashSet = new HashSet<T>();
    return source.Where(item => !hashSet.Add(item))
                 .Distinct().Skip(n - 1) //one based index
                 .FirstOrDefault();
}

答案 2 :(得分:1)

问题是你在计算重复的总数,而不是单个字符的重复数。

已经介绍了一些linq答案,但如果您想知道如何修复现有代码,可以执行以下操作:

public static char returnSecondDuplicate(char[] arr)
{
    if (arr.Length == 0)
        throw new ArgumentNullException("Empty Array passed");
    var dictionary = new Dictionary<char, int>();
    char firstDuplicate = '\0';

    for (int i = 0; i <= arr.Length - 1; i++)
    {

        if (!dictionary.ContainsKey(arr[i]))
        {
            dictionary.Add(arr[i], 1);
        }
        else if (firstDuplicate == '\0')
        {
            firstDuplicate = arr[i];
        }
        else if(arr[i] != firstDuplicate)
        {
            return arr[i];
        }

    }

    return '\0'; //not found
}

基本上,您必须先跟踪哪个字母重复。一旦你有第一个副本,检查后续的不是相同的字母。不同的第一个副本是您想要返回的内容。

答案 3 :(得分:1)

原始代码的问题是,当您看到重复的字符时,每增加时间,但是,您没有检测到它是否已被考虑在内。一个简单的改变是使用一个列表(而不是一个整数)来跟踪重复项。

另外,另一个小的增强(在我看来)是使用while循环而不是for,因为你只想迭代直到满足某些条件,所以它似乎更合适,例如

public static char returnSecondDuplicate(char[] arr)
{
    if (arr.Length == 0)
        throw new ArgumentNullException("Empty Array passed");
    var dictionary = new Dictionary<char, int>();
    var duplicates = new List<char>();
    Char second = '\0';
    int i = 0;

    while (duplicates.Count != 2 && dictionary.Count != arr.Length)
    {
        if (!dictionary.ContainsKey(arr[i]))
            dictionary.Add(arr[i], 1);
        else if (!duplicates.Contains(arr[i]))
            duplicates.Add(arr[i]); // only add duplicates once (ignoring any duplicate duplicates!)

        second = duplicates.Count == 2 ? arr[i] : second;
        i++;
    }

    return second;
}

See it running