1

質問への回答

ダンありがとう!あなたのコードは完璧に機能し、今日私の命を救いました!あなたへの多くのインターネットよろしくお願いします。

オリジナル

前回、リストボックスで重複を見つけるためにLINQを使用するように、コミュニティから寛大に案内されました。ただし、複数列のリストビューから重複を見つけて削除する必要があるため、現在は困難な状況にあります。LINQを使用してみましたが、listviewオブジェクトが「クエリ可能」ではないと表示されます。リストビューの1つの列だけを使用して重複を見つけて削除する方法はありますか?

ありがとう

アップデート

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

これは私がこれまでダンに感謝したことです。「Dimduplicates」行で引き続きエラーが発生します。

UPDATE2 フォーム内のモジュールと関数のコードは次のとおりです。

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さて、2つのオブジェクトが重複しているかどうかを判断するためのいくつかのメソッドが必要になります。

それが整ったら、実装はかなり簡単です。

たとえば、最初の列のテキストが同じである場合、2つの項目が同じであると見なしたいとします。次に、次の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つまり、それぞれのインスタンスを1つ残します。必要な動作が実際に複数回表示されるアイテムのすべてのインスタンスを削除することである場合、アプローチは少し異なります。

これがあなたがそれをすることができる1つの方法です。まず、次の拡張メソッドを定義します。

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 に答える