我想根据子项索引从ListViewItemCollection
删除重复项。
使用LINQ
方法非常重要。
这就是我没有运气的尝试:
Private Function RemoveListViewDuplicates(ByVal Items As ListView.ListViewItemCollection,
ByVal CompareColumn As Integer) As ListView.ListViewItemCollection
Dim Deduplicated =
(From Item As ListViewItem In Items
Group By Item.SubItems(CompareColumn).Text Into Distinct()) '.ToArray
' At this point the good thing is that the '.Distinct' grouped member of the
' resulting 'Deduplicated' object contains only the non-duplicated ListviewItems
' but, I can't find the way to return that single member '.Distinct' as a 'ListView.ListViewItemCollection'
' instead of returning both '.Text' and '.Distinct' members.
'
' I just want to return the 'Items' object that I pass to the function but without duplicates,
' and in the same return-type of the object that I've passed to this function
' (ListView.ListViewItemCollection) as you can understand.
Return Deduplicated
End Function
然后我应该这样做:
Dim items As ListView.ListViewItemCollection =
RemoveListViewDuplicates(ListView1.Items, 0)
For Each Item As ListViewItem In items
MsgBox(Item.Text)
Next Item
更新
我正在尝试解决方案here,但稍加修改以保留集合上的1个重复项目,我遇到的问题是它直接在ListView控件上运行tehn不是我想要的,我想处理一个对象,该对象存储listview控件的当前项,但在删除重复项时不会直接影响控件...
这是方法:
Private Function RemoveListViewDuplicates(ByVal Items As ListView.ListViewItemCollection,
ByVal SubitemCompare As Integer) As ListView.ListViewItemCollection
Dim Duplicates As ListViewItem() =
Items.Cast(Of ListViewItem)().
GroupBy(Function(Item As ListViewItem) Item.SubItems(SubitemCompare).Text).
Where(Function(g As IGrouping(Of String, ListViewItem)) g.Count <> 1).
SelectMany(Function(g As IGrouping(Of String, ListViewItem)) g).
Skip(1).
ToArray()
' This removes the items from the listview control, directlly
For Each Item As ListViewItem In Duplicates
Items.Remove(Item)
Next Item
Return Items
End Function
所需用法:
Dim DuplicatedItems As ListView.ListViewItemCollection =
New ListView.ListViewItemCollection(ListView1)
Dim DeDuplicatedItems As ListView.ListViewItemCollection =
RemoveListViewDuplicates(DuplicatedItems, 0)
' I add the Items without duplicates on another Listview,
' preserving the duplicates on the original Listview1 control.
ListView2.Items.AddRange(DeDuplicatedItems)
答案 0 :(得分:1)
尝试类似下面的例子:
Dim StringList As List(Of String) = ...
StringList = StringList.Distinct().ToList()
的更新强> 的
试试下面的内容。请记住,我习惯于编写C#,所以我可能会留下一些C#。
Option Infer On
Imports System.Linq
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 RemoveListViewDuplicates(ByVal listView As ListView)
Dim duplicates = listView.Items.Cast(Of ListViewItem.SubItems)() _
.GroupBy(Function(item) item.Text) _
.Where(Function(g) g.CountAtLeast(2)) _
.SelectMany(Function(g) g)
For Each duplicate As ListViewItem In duplicates
listView.SubItems.RemoveByKey(duplicate.Name)
Next
End Sub
Private Shared Sub RemoveDuplicateListViewItems(ByVal ListView As ListView.SubItems)
Dim uniqueItems = New HashSet(Of ListViewItem)
For Each item As String In ListView
If !uniqueItems.Add(ListView.Items) Then
ListView.SubItems.RemoveAt(item)
End If
Next
End Sub
答案 1 :(得分:1)
我认为你的方法有2个基本问题。首先,ListViewItems是对象。当它们从ListViewItemCollection中删除时,2个属性会更改:索引(转到0),ListView
(所有者)属性变为Nothing
。因此,当您删除Collection2中的ListViewItem时,还将从主/原始集合中删除,因为它们是相同的LVI对象。
链接到(并在上面复制)的其他SO答案不是一个合适的起点,因为确实想要从您不这样做的源中删除。 解决方案:如果你想要2个具有不同LVI项目的集合(1 == w / dupes; 2 ==没有欺骗),你必须克隆项目 - 要么第一个集合中的所有项目都要从DupesCollection开始或克隆Dupes。我不知道除了循环之外你会怎么做(即通过LINQ)。
如果您在开始时克隆整个集合,您应该可以按照自己的意愿继续沿LINQ路径前进,只需确保您正在处理克隆的集合。这似乎是昂贵的,只是为了能够使用LINQ(尾巴摇尾巴)。
其次,ListViewItemCollection
需要LV所有者。创建其他集合时,您将其分配给特定的LV:
Dim DuplicatedItems As ListView.ListViewItemCollection =
New ListView.ListViewItemCollection(ListView1)
新的集合无法重新分配给不同的LV(看起来你想在不同的LV中显示Dupes)。您无法更改所有者,也无法直接替换Items
。您应该能够在开始时将其分配到所需的目标LV,但将必须克隆项目。否则,将Dupe Items集合移动到LV2的唯一方法是循环播放。
我不确定分配给单个LV的2个LVI集合会发生什么,但是当你真正需要的是重复指数时,制作新集合似乎很昂贵:
' get a list of indices comparing the Text for SubItem(index)
Public Function DuplicateItemIndices(index As Integer) As List(Of Integer)
Dim lvDupes As New List(Of Integer)
If Items.Count = 0 Then Return Nothing
If Items(0).SubItems.Count < index Then Return Nothing
Dim ndx As Integer
For Each lvi As ListViewItem In Items
' already caught, keep going
If lvDupes.Contains(lvi.Index) Then Continue For
ndx = FindDupeItem(lvi, index)
' not sure the second condition can happen here
If ndx > 0 AndAlso lvDupes.Contains(ndx) = False Then
lvDupes.Add(ndx)
End If
Next
Return lvDupes
End Function
' returns an index for an item matching this one
Private Function FindDupeItem(lvi As ListViewItem,
index As Integer) As Integer
For Each lvx As ListViewItem In Items
If lvx Is lvi Then Continue For
If lvx.SubItems(index).Text = lvi.SubItems(index).Text Then
Return lvx.Index
End If
Next
' signal for no match
Return -1
End Function
根据我理解您的目的,使用主列表中返回的List(of DuplicateItemIndices)
到克隆项目并隐藏在DuplicatesLV中。