从多列列表视图中删除重复项

时间:2010-08-30 18:14:25

标签: .net vb.net listview duplicate-removal

已回答问题

谢谢Dan!你的代码完美无缺,今天你救了我的命!很多互联网给你好先生。

原始

我受到社区的慷慨指导,使用LINQ最后一次在我的列表框中查找重复项。但是,我现在处于困境,因为我需要从多列列表视图中查找和删除重复项。我尝试使用LINQ,但它说listview对象不是“可查询的”。有没有办法让我只使用listview的一列来查找和删除重复项?

由于

更新

Private Shared Sub RemoveDuplicateListViewItems(ByVal listView As ListView)
    Dim duplicates = listView.Items.Cast(Of ListViewItem)() _
    .GroupBy(Function(item) item.Text)
    .Where(Function(g) g.CountAtLeast(2))
    .SelectMany(Function(g) g)

    For Each duplicate As ListViewItem In duplicates
        listView.Items.RemoveByKey(duplicate.Name)
    Next
End Sub

这是我迄今为止感谢丹。仍然在“Dim duplicatelicates”行上出现错误。

更新2 以下是表单中模块和函数的代码:

Imports System.Runtime.CompilerServices

Module CountAtLeastExtension
    <Extension()> _
    Public Function CountAtLeast(Of T)(ByVal source As IEnumerable(Of T), ByVal minimumCount As Integer) As Boolean
        Dim count = 0
        For Each item In source
            count += 1
            If count >= minimumCount Then
                Return True
            End If
        Next

    Return False
End Function
End Module

    Private Shared Sub RemoveDuplicateListViewItems(ByVal listView As ListView)
    Dim duplicates = listView.Items.Cast(Of ListViewItem)() _
        .GroupBy(Function(item) item.Text) _
        .Where(Function(g) g.CountAtLeast(2)) _
        .SelectMany(Function(g) g)

    For Each duplicate As ListViewItem In duplicates
        listView.Items.RemoveByKey(duplicate.Name)
    Next
End Sub

我打电话给代码现在运行正常。但它并没有删除重复项:

Example of a duplicate

也许通过这个截图你可以看到我在这里要做什么。非常感谢你对我这么耐心!

1 个答案:

答案 0 :(得分:1)

好吧,你需要一些方法来确定两个ListViewItem对象是否重复。

一旦到位,实施就相当简单。

假设您想要考虑两个项目,如果第一列中的文本相同(例如)。然后,您可以编写一个快速IEqualityComparer<ListViewItem>实现,例如:

class ListViewItemComparer : IEqualityComparer<ListViewItem>
{
    public bool Equals(ListViewItem x, ListViewItem y)
    {
        return x.Text == y.Text;
    }

    public int GetHashCode(ListViewItem obj)
    {
        return obj.Text.GetHashCode();
    }
}

然后您可以删除重复项:

static void RemoveDuplicateListViewItems(ListView listView)
{
    var uniqueItems = new HashSet<ListViewItem>(new ListViewItemComparer());

    for (int i = listView.Count - 1; i >= 0; --i)
    {
        // An item will only be added to the HashSet<ListViewItem> if an equivalent
        // item is not already contained within. So a return value of false indicates
        // a duplicate.
        if (!uniqueItems.Add(listView.Items[i]))
        {
            listView.Items.RemoveAt(i);
        }
    }
}

更新:上述代码会多次删除ListView中出现的任何项目的重复;也就是说,它会留下每个实例。如果您想要的行为实际上是删除多次出现的任何项目的所有实例,则该方法会略有不同。

这是你可以做到的一种方式。首先,定义以下扩展方法:

public static bool CountAtLeast<T>(this IEnumerable<T> source, int minimumCount)
{
    int count = 0;
    foreach (T item in source)
    {
        if ((++count) >= minimumCount)
        {
            return true;
        }
    }

    return false;
}

然后,找到像这样的重复:

static void RemoveDuplicateListViewItems(ListView listView)
{
    var duplicates = listView.Items.Cast<ListViewItem>()
        .GroupBy(item => item.Text)
        .Where(g => g.CountAtLeast(2))
        .SelectMany(g => g);

    foreach (ListViewItem duplicate in duplicates)
    {
        listView.Items.RemoveByKey(duplicate.Name);
    }
}

更新2 :听起来您已经能够将上述大部分内容转换为VB.NET了。给您带来麻烦的那一行可以写成如下:

' Make sure you have Option Infer On. '
Dim duplicates = listView.Items.Cast(Of ListViewItem)() _
    .GroupBy(Function(item) item.Text) _
    .Where(Function(g) g.CountAtLeast(2)) _
    .SelectMany(Function(g) g)

另外,如果以上述方式使用CountAtLeast方法时遇到任何问题,则需要使用ExtensionAttribute类在VB.NET中编写扩展方法:

Module CountAtLeastExtension

    <Extension()> _
    Public Function CountAtLeast(Of T)(ByVal source As IEnumerable(Of T), ByVal minimumCount As Integer) As Boolean
        Dim count  = 0
        For Each item in source
            count += 1
            If count >= minimumCount Then
                Return True
            End If
        Next

        Return False
    End Function

End Module