1

已回答的问题

谢谢丹!您的代码运行良好,您今天救了我的命!很多互联网给你好先生。

原来的

上次社区慷慨地指导我使用 LINQ 在我的列表框中查找重复项。但是,我现在处境艰难,因为我需要从多列列表视图中查找和删除重复项。我尝试使用 LINQ,但它说 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 duplicates”行上仍然出现错误。

更新 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

当我调用它时,代码现在运行良好。但它不会删除重复项:

副本示例

也许通过这个截图,你可以看到我在这里的目的。非常感谢你对我这么有耐心!

4

1 回答 1

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
于 2010-08-30T18:57:04.967 回答