C#计算List <string> </string>中的连续重复项

时间:2014-08-21 14:13:29

标签: c# performance list duplicates

我有一个字符串列表,并希望计算其中的重复项,以便稍后处理此信息。简单地计算重复数据将非常容易,但遗憾的是我只想计算连续重复数。

我们假设我们有一个包含此字符串项的列表:

  

“1A”, “3B”, “5X”, “7Q”, “2W”, “2G”, “2J”, “1A”, “2A”

现在我想计算此列表中的重复项。 我只会查看每个字符串的第一个字符,字符串中的其他字符可以忽略! 我们得到的是 2x“1%”和 3x“2%”,我实际想要的是连续重复,所以我的结果看起来应该是 3x “2%”。必须忽略 2x“1A”,它们不在一行中。 (%=占位符)

我编写了一个循环遍历列表的代码,并将一个字符串与下一个字符串进行比较

int counter = 0;
for (int i = 0; i < list.Count; i++)
{
    char first = list[i][0];

    if ((i + 1) == list.Count) break;
    char second = list[(i + 1)][0];

    if (first == second)
    {
        counter++;
    }
}

我猜你可以想象这个代码是一种非常难看的方式,特别是如果你想使用输出。我的代码也无法处理我需要的功能。

我正在寻找的代码,必须能够处理我想要实现的两个功能。首先,如果列表的最后一个元素等于列表的第一个元素,则一行重复项不会结束。

例如:

  

“1A”, “1B”, “5X”, “7Q”, “2J”, “1I”

“1%”必须被检测为重复,因为“1I”和“1A”是“连续”的。如果你要循环遍历列表,如果第一个和最后一个元素不相等,你就会在列表的末尾分解。

伪代码:

if(list.First()[0] != list.Last()[0])

我要实现的第二个功能是,列表中不重复的项目,“重复计数”超过4将被删除。如果没有一个重复的行具有“重复计数”或长度超过4,我想返回。

例如:

  

“1A”, “1B”, “5X”, “3Q”, “1J”, “1I”

重复计数== 4所以返回

  

“1A”, “1B”, “1X”, “3Q”, “1J”, “1I”

重复count == 5,保存这五项,删除列表中的任何其他项目。

  

“1A”, “1B”, “1X”, “3Q”, “1I”, “1Z”, “1Z”

重复计数== 6,保存这六项,删除列表中的任何其他项目。

注意: 只是每个字符串的第一个字符很重要。输入列表将包含7个项目,而不是单个项目或多或少。没有结果列表,旧的必须更新。如果重复计数小于或等于4,则无需做任何工作,只需返回即可。 连续不会超过5个重复。我必须检查十亿个列表,因此性能非常重要

由于他们没有在德国学校教过更好的英语,我希望有人能理解我的问题是什么,并愿意帮助我。

这不是任何家庭作业的一部分。

2 个答案:

答案 0 :(得分:2)

这里可以使用的是一种能够在满足条件时对连续项进行分组的方法:

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        List<T> list = new List<T>() { iterator.Current };

        T previous = iterator.Current;

        while (iterator.MoveNext())
        {
            if (!predicate(previous, iterator.Current))
            {
                yield return list;
                list = new List<T>();
            }

            list.Add(iterator.Current);
            previous = iterator.Current;
        }
        yield return list;
    }
}

一旦我们有了这个帮助方法,我们就可以用一个相当直接的庄园来编写你的查询:

var query = data.GroupWhile((prev, current) => prev[0] == current[0])
    .Where(group => group.Count() > 1)
    .Select(group => new
    {
        Character = group.First()[0],
        Count = group.Count(),
    });

答案 1 :(得分:0)

我建议你将列表中以相同字符开头的项目分组。此分组的结果将是List<List<string>>。这样可以更轻松地使用组。

var list = new List<string> {
    "1A", "3B", "5X", "7Q", "2W", "2G", "2J", "1B", "1C", "1D", "1E"
};
var groups = new List<List<string>>();

char lastChar = (char)0; // We assume that NUL will never be used as first char.
List<string> group = null;
foreach (string s in list) {
    if (s[0] != lastChar) {
        group = new List<string>();
        groups.Add(group);
        lastChar = s[0];
    }
    group.Add(s);
}

// Join the first and the last group if their first char is equal
int lastIndex = groups.Count - 1;
if (groups.Count > 2 && groups[0][0][0] == groups[lastIndex][0][0]) {
    // Insert the elements of the last group to the first group
    groups[0].InsertRange(0, groups[lastIndex]);
    // and delete the last group
    groups.RemoveAt(lastIndex);
}

//TODO: Remove test
foreach (List<string> g in groups) {
    Console.WriteLine(g[0][0]);
    foreach (string s in g) {
        Console.WriteLine("   " + s);
    }
}

// Now create a list with items of groups having more than 4 duplicates 
var result = new List<string>();
foreach (List<string> g in groups) {
    if (g.Count > 4) {
        result.AddRange(g);
    }
}

//TODO: Remove test
Console.WriteLine("--------");
foreach (string s in result) {
    Console.Write(s);
    Console.Write("  ");
}
Console.WriteLine();
Console.ReadKey();