我知道在这个问题上有很多类似的问题,但我找不到我想要的答案。这是我的要求。
我有很长的字符串列表(很容易超过50,000或甚至100K项目),我需要在其中找到重复的项目。但只是发现重复不会做;我真正想要做的是浏览列表并在每个项目的末尾添加一个增量索引,以指示项目重复的次数。为了更好地说明,让我举一个例子。我的列表实际上包含路径,因此示例大致类似于。
我原来的名单:
AAA\BBB
AAA\CCC
AAA\CCC
BBB\XXX
BBB
BBB\XXX
BBB\XXX
我的调整后的列表添加了索引:
AAA\BBB[1]
AAA\CCC[1]
AAA\CCC[2]
BBB\XXX[1]
BBB[1]
BBB\XXX[2]
BBB\XXX[3]
首先,我使用Linq尝试了以下方法:
List<string> originalList = new List<string>();
List<string> duplicateItems = new List<string>();
// pathList is a simple List<string> that contains my paths.
foreach (string item in pathList)
{
// Do some stuff here and pick 'item' only if it fits some criteria.
if (IsValid(item))
{
originalList.Add(item);
int occurences = originalList.Where(x => x.Equals(item)).Count();
duplicateItems.Add(item + "[" + occurences + "]");
}
}
这很好用,给了我想要的结果。问题是,由于我的列表可以包含100K项目,因此速度很慢。所以我环顾四周,了解到HashSet可能是一种可能更有效的替代品。但我无法弄清楚如何使用它来获得我想要的结果。
我可以尝试这样的事情,我想:
HashSet<string> originalList = new HashSet<string>();
List<string> duplicateItems = new List<string>();
foreach (string item in pathList)
{
// Do some stuff here and pick 'item' only if it fits some criteria.
if (IsValid(item))
{
if (!originalList.Add(item))
{
duplicateItems.Add(item + "[" + ??? + "]");
}
}
}
后来我可以添加&#34; [1]&#34;对于HashSet中的所有项目,但是如何在将项目添加到重复列表时将索引设置为正确(由混淆的通用符号,上面标记为???)?我不能保留一个我可以传递给我的方法的引用int,因为可能有数百个不同的重复项,每个重复项都重复不同的次数。
我仍然可以使用HashSet,还是有更好的方法来实现我的目标?即使是朝着正确方向的微小指针也会有很大的帮助。
答案 0 :(得分:9)
由于您要求最快,最好的IMO将使用foreach
循环并计算Dictionary<string, int>
。它具有与HashSet
相同的时间复杂度,并且使用的内存比LINQ GroupBy
少得多:
var counts = new Dictionary<string, int>(pathList.Count); // specify max capacity to avoid rehashing
foreach (string item in pathList)
{
// Do some stuff here and pick 'item' only if it fits some criteria.
if (IsValid(item))
{
int count;
counts.TryGetValue(item, out count);
counts[item] = ++count;
duplicateItems.Add(item + "[" + count + "]");
}
}
答案 1 :(得分:3)
你可以试试这个,虽然我还没有进行过性能测试:
List<string> originalList = new List<string>()
{
@"AAA\BBB",
@"AAA\CCC",
@"AAA\CCC",
@"BBB\XXX",
@"BBB",
@"BBB\XXX",
@"BBB\XXX"
};
List<string> outputList = new List<string>();
foreach(var g in originalList.GroupBy(x => x).Select(x => x.ToList()))
{
var index = 1;
foreach(var item in g)
{
outputList.Add(string.Format("{0}[{1}]", item, index++));
}
}
小提琴here
答案 2 :(得分:1)
这个怎么样?
{{1}}
答案 3 :(得分:1)
您可以遍历列表并使用字典来获取计数,如下所示:
C:\dlib-19.4\dlib-19.4\dlib
答案 4 :(得分:1)
你可以使用这个清脆而脆脆的代码:
public static void Main()
{
var originalList = new List<string>()
{
@"AAA\BBB",
@"AAA\CCC",
@"AAA\CCC",
@"BBB\XXX",
@"BBB",
@"BBB\XXX",
@"BBB\XXX"
};
var outputList = originalList.GroupBy(x => x).SelectMany(x => x.Select((y, i) => string.Format("{0}[{1}]", y, i + 1)));
Console.WriteLine(string.Join("\n", outputList));
}
答案 5 :(得分:0)
您可以使用Group()将字符串拉到一起,然后使用值和计数的组合来投影这些组。
给出你的字符串列表:
var listOfStrings;
var grouped = listOfStrings.GroupBy(x => x);
var groupedCount = grouped.Select(x => new {key = x.Key, count = group.Count()});