var duplicates = lst.GroupBy(s => s)
.SelectMany(grp => grp.Skip(1));
请注意,这将返回所有的重复项。因此,如果您只想知道源列表中有哪些项目是重复的,您可以对结果序列应用Distinct
或使用Mark Byers提供的解决方案。
GroupBy
中有一个重载函数,它允许您提供一个IEqualityComparer
以代替使用ToUpper
进行不区分大小写的比较。 - Lee以下是一种实现方法:
List<String> duplicates = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
GroupBy
按相同的元素进行分组,Where
筛选出只出现一次的元素,留下重复的元素。
这里还有一种选择:
var list = new List<string> { "6", "1", "2", "4", "6", "5", "1" };
var set = new HashSet<string>();
var duplicates = list.Where(x => !set.Add(x));
.Where
中使用副作用应该被避免,所以这可能是原因。 - Paul Groke我知道这不是原问题的答案,但你可能会在这里遇到同样的问题。
如果你想要结果中所有的重复项,以下方法有效。
var duplicates = list
.GroupBy( x => x ) // group matching items
.Where( g => g.Skip(1).Any() ) // where the group contains more than one item
.SelectMany( g => g ); // re-expand the groups with more than one item
在我的情况下,我需要所有的重复项,以便我可以在用户界面中将它们标记为错误。我根据@Lee对OP的回答编写了这个扩展方法。请注意,默认参数使用了C# 4.0(需要)。然而,在C# 3.0中,重载的方法调用也足够。
/// <summary>
/// Method that returns all the duplicates (distinct) in the collection.
/// </summary>
/// <typeparam name="T">The type of the collection.</typeparam>
/// <param name="source">The source collection to detect for duplicates</param>
/// <param name="distinct">Specify <b>true</b> to only return distinct elements.</param>
/// <returns>A distinct list of duplicates found in the source collection.</returns>
/// <remarks>This is an extension method to IEnumerable<T></remarks>
public static IEnumerable<T> Duplicates<T>
(this IEnumerable<T> source, bool distinct = true)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
// select the elements that are repeated
IEnumerable<T> result = source.GroupBy(a => a).SelectMany(a => a.Skip(1));
// distinct?
if (distinct == true)
{
// deferred execution helps us here
result = result.Distinct();
}
return result;
}
List<String> list = new List<String> { "6", "1", "2", "4", "6", "5", "1" };
var q = from s in list
group s by s into g
where g.Count() > 1
select g.First();
foreach (var item in q)
{
Console.WriteLine(item);
}
int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
.GroupBy(i => i)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
foreach (var d in duplicates)
Console.WriteLine(d);
我曾尝试通过对象列表进行解决,但是因为我试图重新装入组列表到原始列表中,所以遇到了问题。因此,我想出了通过循环遍历组来重装具有重复元素的项目到原始列表中。
public List<MediaFileInfo> GetDuplicatePictures()
{
List<MediaFileInfo> dupes = new List<MediaFileInfo>();
var grpDupes = from f in _fileRepo
group f by f.Length into grps
where grps.Count() >1
select grps;
foreach (var item in grpDupes)
{
foreach (var thing in item)
{
dupes.Add(thing);
}
}
return dupes;
}
到目前为止,所有提到的解决方案都执行了GroupBy操作。即使我只需要第一个重复项,集合中的所有元素至少被枚举一次。
下面的扩展函数在找到重复项后立即停止枚举。如果请求下一个重复项,它会继续执行。
像LINQ中的其他情况一样,有两个版本,一个带有IEqualityComparer,一个没有。
public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource> source)
{
return source.ExtractDuplicates(null);
}
public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource source,
IEqualityComparer<TSource> comparer);
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (comparer == null)
comparer = EqualityCompare<TSource>.Default;
HashSet<TSource> foundElements = new HashSet<TSource>(comparer);
foreach (TSource sourceItem in source)
{
if (!foundElements.Contains(sourceItem))
{ // we've not seen this sourceItem before. Add to the foundElements
foundElements.Add(sourceItem);
}
else
{ // we've seen this item before. It is a duplicate!
yield return sourceItem;
}
}
}
使用方法:
IEnumerable<MyClass> myObjects = ...
// check if has duplicates:
bool hasDuplicates = myObjects.ExtractDuplicates().Any();
// or find the first three duplicates:
IEnumerable<MyClass> first3Duplicates = myObjects.ExtractDuplicates().Take(3)
// or find the first 5 duplicates that have a Name = "MyName"
IEnumerable<MyClass> myNameDuplicates = myObjects.ExtractDuplicates()
.Where(duplicate => duplicate.Name == "MyName")
.Take(5);
对于所有这些linq语句,集合只会被解析直到找到所请求的项。其余的序列不会被解释。
在我看来,这是一个值得考虑的效率提升。
HashSet<T>.Contains + Add
的组合简化为只使用 Add
。这样可以避免额外的查找成本。例如,在你的情况下:if (!foundElements.Add(sourceItem)) yield return sourceItem;
这就是你所需要的。 - nawfal