从多列列表视图中删除重复的项目 [英] Removing duplicate items from a multicolumn listview

查看:223
本文介绍了从多列列表视图中删除重复的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已回答的问题

谢谢丹!你的代码工作完美,你今天救了我的生命!许多互联网给你很好的先生。

Thank you Dan! Your code worked perfectly and you saved my life today! Many internets to you good sir.

原始

我被慷慨的指导社区最后一次使用LINQ找到我的列表框上的重复项。但是,我现在处于困难的境地,因为我需要从多列列表视图中查找和删除重复项。我尝试使用LINQ,但它表示listview对象不是可查询。有一种方法可以使用列表视图的一列查找和删除重复项吗?

I was generously guided by the community to use LINQ to find duplicates on my listboxes the last time around. However, I am now in a tough spot because I need to find and remove duplicates from a multicolumn list view. I tried using LINQ but it says that the listview object is not "queryable". Is there a way for me to find and remove duplicates using only one column of the 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

这是我迄今为止感谢丹。

This is what I have so far thanks to Dan. Still getting errors on the "Dim duplicates" line.

更新2
这里是模块和函数内部的代码形式:

UPDATE 2 Here is the code for the Module and the Function inside the form:

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

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

The code now runs fine when I call it. But it does not remove the duplicates:

一个重复的例子

也许这个截图你可以看到我要去这里。非常感谢您对我的耐心等待!

Maybe with this screenshot you can see what I am going for here. Thank you very much for being so patient with me!

推荐答案

嗯,你需要一些确定两个 ListViewItem 对象是重复的。

Well, you'll need some method for determining whether two ListViewItem objects are duplicates.

一旦这样做,实现是相当简单的。

Once that's in place, the implementation is fairly straightforward.

如果第一列中的文本相同(例如),则要考虑两个项目相同。那么你可能会写出一个快速的 IEqualityComparer< ListViewItem> 实现,例如:

Let's say you want to consider two items to be the same if the text in the first column is the same (for example). Then you might write up a quick IEqualityComparer<ListViewItem> implementation such as:

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();
    }
}

然后你可以删除这样的重复:

Then you could remove duplicates like so:

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 中显示的任何项目的重复一旦;也就是说,它留下了一个实例。如果您想要的行为实际上是删除出现不止一次的任何项目的所有实例,则该方法有所不同。


UPDATE: The above code removes the duplicates of any items that appear in the ListView more than once; that is, it leaves one instance of each. If the behavior you want is actually to remove all instances of any items that appear more than once, the approach is a little bit different.

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

Here's one way you could do it. First, define the following extension method:

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;
}

然后,如下所示找到重复项:

Then, find duplicates like so:

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。给你麻烦的那一行可以写成如下:


UPDATE 2: It sounds like you've been able to convert most of the above to VB.NET already. The line that is giving you trouble can be written as follows:

' 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中编写扩展方法:

Also, in case you have any trouble using the CountAtLeast method in the above way, you need to use the ExtensionAttribute class to write extension methods in 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

这篇关于从多列列表视图中删除重复的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆