【问题标题】:Get most/least sold items in C# datatable在 C# 数据表中获取最多/最少销售的商品
【发布时间】:2013-08-28 19:06:45
【问题描述】:

我正在创建一个 C# WPF 应用程序,让用户接受订单(想想餐厅/酒吧)。

为简单起见,我将订单限制为单件商品的简单购买(您可以购买多件商品,例如购买 4 瓶啤酒)。每个购买都记录为一个 Purchase 对象:

class Purchase
{
    public int id {get;set;}
    public DateTime time {get;set;}
    public double price {get;set;}
    public int quantity {get;set;}
}

每次购买都会被添加到数据表中。

我想在给定时间内获得 3 个最多购买和 3 个最少购买的商品,但我无法为此编写合适的查询。

到目前为止,我所拥有的是这个,但它不起作用:

 public List<int> GetMostBought()
    {
        DateTime lastMinute = DateTime.UtcNow.Add(new TimeSpan(0, -1, 0)); //one minute ago
        int howMany = 3; // how many items to get.
        var query =
           (from p in purchases.AsEnumerable()
            where p.Field<DateTime>("time")>= lastMinute //purchases made less than a minute ago
            select new { Product = p, Quantity = p.Field<int>("quantity") } into productQty
            group productQty by productQty.Product into pg
            let totalQuantity = pg.Sum(prod => prod.Quantity)
            orderby totalQuantity descending
            select pg.Key).Take(howMany);

        List<int> mostBoughtIDs = new List<int>();
        foreach (DataRow dr in query)
        {
            mostBoughtIDs.Add(Int32.Parse(dr[0].ToString()));
        }
        return mostBoughtIDs;

有什么想法吗?

【问题讨论】:

    标签: c# linq datatable linq-to-objects nested-queries


    【解决方案1】:
    var mostBoughtIDs = purchases.AsEnumerable()
                                 .Where(r=>r.Field<DateTime>("time")>= lastMinute)
                                 .GroupBy(r=>r.Field<int>("id"))
                                 .OrderByDescending(g=>g.Sum(r=>r.Field<int>("quantity"))
                                 .Select(g=>g.First().Field<int>("id"))
                                 .Take(howMany);
    

    【讨论】:

    • 我得到一个“'System.Data.DataRow' 不包含'id' 的定义并且没有扩展方法'id' 接受'System.Data.DataRow' 类型的第一个参数可能是在选择行(在 .id)上发现“错误是否缺少其他内容?
    • 您的数据表中是否有一个名为“id”的列?我们假设您的 DataTable 反映了您定义的对象。
    • @ConnorU 只有Where 可以影响这一点,您应该确保lastMinute 具有适当的值,以便过滤结果应包含至少1 个项目。
    • 我终于抓住了它,我现在一次使用 UTC,另一次使用基本现在。感谢一切!你的代码现在可以运行了,有一个我很想弄清楚的错误,但我可以处理它。
    【解决方案2】:

    考虑到这一点,我的答案几乎与国王国王相同......

    var items = 
        purchases.AsEnumerable()
        .Where(e => e.Field<DateTime>("time") >= lastMinute)
        .GroupBy( g => g.Field<int>("id") )
        .OrderByDecending( i => i.Sum( e => e.Field<int>("quantity") ) )
        .Select( g => g.First().Field<int>("id"))
        .Take(3)
    

    【讨论】:

    • 哦,我应该删除该评论,我正在使用数量字段,更重要的是,我希望查询能够处理未来的数量。还是谢谢
    • 你的答案返回一个空列表,KingKing's :/
    【解决方案3】:

    您可以使用 here 找到的一个不错的小方法从 List 创建 DataTable:

    public DataTable ConvertToDataTable<T>(IList<T> data)
        {
            PropertyDescriptorCollection properties =
               TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                table.Rows.Add(row);
            }
            return table;
    
        }
    
    public List<int> GetMostAndLeastBought(int howMany){
    List<Purchase> purchasesList = new List<Purchase>{
                                                new Purchase{ id = 1, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 1, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 2, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 2, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 3, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 3, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 4, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 4, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 5, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 6, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1},
                                                new Purchase{id = 7, time = DateTime.UtcNow.Add(new TimeSpan(0, 0, -1)), quantity = 1}                                                                              
                                            };
    
            DataTable purchases = ConvertToDataTable(purchasesList);
    

    我认为查询语法在这里也适用于主查询:

     DateTime lastMinute = DateTime.UtcNow.Add(new TimeSpan(0, -1, 0)); //one minute ago  
    
    var query = from p in purchases.AsEnumerable()
                where p.Field<DateTime>("time") >= lastMinute
                group p by p.Field<int>("id") into g                    
                select new {Id = g.Key, TotalQuantity = g.Sum(x => x.Field<int>("quantity"))} into s
                orderby s.TotalQuantity descending, s.Id
                select s.Id;
    

    如果您愿意,您可以同时获得最多和最少。你想在两者都做之前转换 List ,因为这样你就可以有效地获取最后一个元素,如下所示:

    var list = query.ToList();
    
    var most = list.GetRange(0, howMany);
    var least = list.GetRange(list.Count - howMany, howMany);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-26
      • 2016-01-19
      • 2017-08-18
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多