计算 ListView 列中的所有重复项。 C#

Count all duplicates in ListView column. C#

我正在为市场创建一个软件,并想创建一个列表视图来计算列中的所有重复值。

此计数将显示买家经常购买的商品数量。

这才是ListView应该有的概念。 从ListView1的列开始统计,把重复的放到ListView2里面统计,显示数据。

我需要知道:

注意:在这种情况下,“名称”中的值是一个项目,“已购买的项目”是一个子项目。这些数据来自简单地在文本框中键入并单击按钮。

可以使用 System.Linq.GroupBy 逻辑和 DataGridView(Winforms 示例)视图来实现您想要的结果:

写的代码量小!只需对两个列表使用数据绑定 Winforms, Xamarin, WPF

首先制作两个类包含您希望显示的属性:

internal class UserPurchase
{       
    public string Name { get; internal set; } // Internal makes item ReadOnly in view
    public string Purchase { get; internal set; }
}

internal class PurchasedItem
{
    public string Description { get; internal set; }
    public int Count { get; internal set; }
}

然后声明两个BindingList(Winforms示例)或ObservableCollection(其他)。

internal BindingList<UserPurchase> PurchasesByUser { get; } = new BindingList<UserPurchase>();
internal BindingList<PurchasedItem> PurchasedByItem { get; } = new BindingList<PurchasedItem>();

这显示了如何在 Winforms 中附加绑定(对于其他平台,请使用 xaml)。因此 DataGridView 现在将使用两个 类.

的属性自动生成列
protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    if (!DesignMode)
    {
        // Bind the lists to the UI element to display them.
        dataGridView1.DataSource = PurchasesByUser;
        dataGridView2.DataSource = PurchasedByItem;
        initList1();
    }
}

这是填充 List1 PurchasesByUser 然后在 List1 上应用 System.Linq.GroupBy 来计算 List2 PurchasedByItem:

private void initList1()
{
    XElement xsource = XElement.Parse(source);
    XElement[] xusers = xsource.Elements("user").ToArray();
    foreach (XElement xuser in xusers)
    {
        XElement[] xpurchases = xuser.Element("items").Elements("item").ToArray();
        foreach (XElement xpurchase in xpurchases)
        {
            var xname = xuser.Element("name");
            // Every time you add a record to the list, it appears in the View automatically.
            PurchasesByUser.Add(new UserPurchase { Name = (string)xname, Purchase = (string)xpurchase });
        }
    }
    // Make what is essentially a list *of* lists using System.Linq.GroupBy
    var groups = 
        PurchasesByUser.GroupBy(purchase => purchase.Purchase);
    foreach (var group in groups)
    {
        // Decoding the Group:
        Debug.WriteLine(
            $"The group '{group.Key}' holds {group.Count()} items");
        Debug.WriteLine(
            $"The customers are { string.Join(",", group.ToList().Select(item=>item.Name))}");
        var byItem = new PurchasedItem { Description = group.Key, Count = group.Count() };
        PurchasedByItem.Add(byItem);
    }
}

最后 为您的数据库建模(带有子项),我使用 Xml 格式的字符串:

const string source =
    @"<purchases>
        <user>
            <name>John Doe</name>
            <items>
                <item>Shoes</item>
                <item>T-Shirts</item>
                <item>Jeans</item>
            </items>
        </user>
        <user>
            <name>Rick Astley</name>
            <items>
                <item>Baseball bat</item>
                <item>Sandwich</item>
                <item>T-Shirts</item>
                <item>Shoes</item>
            </items>
        </user>
        <user>
            <name>Jane Doe</name>
            <items>
                <item>Shoes</item>
                <item>T-Shirts</item>
            </items>
        </user>
        <user>
            <name>Anonymous</name>
            <items>
                <item>Laptop</item>
            </items>
        </user>
        <user>
            <name>Joe Mm.</name>
            <items>
                <item>Milk</item>
                <item>Shoes</item>
            </items>
        </user>
    </purchases>";

这当然只是一种方法,但您的问题是演示结合 System.Linq System.Xml.Linq 和数据绑定概念的好方法。如果您想试验一下,我已将我的代码发布在 GitHub 上。

那么,如果我知道你想要另一个包含重复项和计数的列表视图?

如果是这样,您可以创建一个 List<>,然后将该项目添加到列表中,我相信在这种情况下将是一个字符串,也许是这样的?这只是一个用于演示的控制台应用程序。

List<string> myList = new List<string>();

myList.Add("One");
myList.Add("Two");
myList.Add("Three");
myList.Add("One");
myList.Add("Two");
myList.Add("Four");

List<string> noDupes = myList.Distinct().ToList();


foreach(string dupe in noDupes)
{
    Console.WriteLine(dupe);
}

Console.WriteLine(noDupes.Count());

给定下一个列表:

List<myClass> items = new List<myClass>()
{
    new myClass() { Name = "John Doe", Item = "Shoes" },
    new myClass() { Name = "John Doe", Item = "T-Shirt" },
    new myClass() { Name = "John Doe", Item = "Jeans" },
    new myClass() { Name = "Rick Astley", Item = "Baseball bat" },
    new myClass() { Name = "Rick Astley", Item = "Sandwich" },
    new myClass() { Name = "Rick Astley", Item = "T-Shirt" },
    new myClass() { Name = "Rick Astley", Item = "Shoes" },
    new myClass() { Name = "Jane Doe", Item = "Shoes" },
    new myClass() { Name = "Jane Doe", Item = "T-Shirt" },
    new myClass() { Name = "Joe Mm.", Item = "Shoes" },
    new myClass() { Name = "Joe Mm.", Item = "Milk" },
};

可以这样分组统计:

var l = items.GroupBy(group => group.Item)
                .Select(n => new { Item = n.Key, Count = n.Count() })
                .ToList();

结果:

Item: Shoes  Count: 4
Item: T-Shirt  Count: 3
Item: Jeans  Count: 1
Item: Baseball bat  Count: 1
Item: Sandwich  Count: 1
Item: Milk  Count: 1

将输入 ListView 的项目按第二个 ColumnHeader(索引 = 1)的值分组得到 IEnumerable<IGrouping<string, ListViewItem>>,然后使用元素(类型 IGrouping<string, ListViewItem>) Key 属性 和 Count 方法创建输出 ListView.

ListViewItem 对象

这是一个衬垫:

listView2.Items.AddRange(listView1.Items
    .Cast<ListViewItem>()
    .GroupBy(x => x.SubItems[1].Text, StringComparer.OrdinalIgnoreCase)
    .Select(x => new ListViewItem(new[] { x.Key, x.Count().ToString() }))
    .ToArray());