【问题标题】:Utilizing a Queue [closed]利用队列[关闭]
【发布时间】:2013-10-23 20:31:30
【问题描述】:

我正在尝试按类别存储过去 1、7、30 或 360 天的所有交易记录。我尝试了几件事,但它们都失败了。我有一个想法,使用具有 360 个值的队列,每天一个,但我对队列的了解不够,无法弄清楚它是如何工作的。

输入将是此类的一个实例:

class Transaction
{
    public string TotalEarned { get; set; }
    public string TotalHST { get; set; }
    public string TotalCost { get; set; }
    public string Category { get; set; }
}

一天中的任何时间都可能发生新的交易,一天最多可以有 15 笔交易。我的程序使用纯文本文件作为外部存储,但我如何加载它取决于我决定如何存储这些数据。

最好的方法是什么?

【问题讨论】:

  • 你如何加载它应该取决于你打算用它做什么。你打算用Transactions 做什么?如果您想按顺序单独处理它们,Queue 很有用。
  • 您不应该删除您的问题并重新提问;如果您有新信息要提供,您只需编辑您的old question。最重要的是,我仍然没有看到足够的信息来了解您到底想要什么。
  • 队列或列表或堆栈可以稍后决定。你的课对我来说似乎不合适。它没有足够的信息来存储交易发生的时间
  • What would be the best way to do this? 做什么?不清楚问题是什么?您想按 1、7、30 和 360 天的类别收集东西吗?第 1 步,接受 @MillerKoijam 的建议并添加一个 DateTime。然后,您可以将它们分组。存储与分类有什么关系?

标签: c# .net list queue


【解决方案1】:

我不确定队列是否正是您在此处寻找的。队列是一种短暂的数据结构:它的目的不是让事情暂时存在,当然也不是为了让您以您想要的方式对数据进行切片和切块。

听起来您的用例急需数据库。长期存储结构化数据,以按各种标准进行排序或查询,这正是数据库的发明目的。

【讨论】:

  • 结构化数据库的实现有多容易?由于它们的简单性,我一直使用 .txt 文件,但如果使用数据库足够简单,我可能会进行切换。编辑:这就是我现在做数据库的方式:
  • 在项目中使用数据库肯定会产生开销:设置和运行数据库服务器、添加客户端库、创建表模式以及编写查询以插入和选择数据。幸运的是,微软让在 .NET 项目上开始使用 MSSQL 变得非常容易,因为大部分配置都是开箱即用的。
【解决方案2】:

您显然追求的是便利而不是速度。您期望的典型用法总共存储大约 5400 笔交易。这真的很小,单个ArrayList 应该没问题。当您想从中查询数据时,只需遍历它,将相关项目添加到另一个 ArrayList 并返回。

只需按排序顺序保存您的数据 - 所有新交易都会被推到列表的后面。如果你想按类别拉出,那应该和按天拉出一样简单。

保持单一结构并从中复制查询将使您的生活更轻松,尤其是当您的类在多个线程中使用并需要锁定时。

对我来说,维护索引以加快查找速度或使用数据库似乎有点过头了。如果一个简单的解决方案足够好,那么就使用它。它更易于维护且不易出错。

【讨论】:

  • 这个,加上从纪元开始到添加到课堂的天数的秒数可能会起作用,我会试一试!谢谢!
  • 如果数据在逻辑上代表一个队列,那么您应该使用队列而不是ArrayList。除了表现更好之外,如果它是数据逻辑表示的内容,那么使用队列将变得更容易。另请注意,ArrayList 已完全弃用;至少使用List
  • 感谢@Servy,我以 C# 知识有限的 C++ 程序员的身份回答。我不认为这与语言有关,而是与设计考虑因素有关。
【解决方案3】:

在决定数据存储之前,您应该考虑要对数据执行的操作。对我来说,听起来你想要

  • 按日期和时间段查询
  • 让集合根据其包含的数据的年龄自行清除

编写一个自定义类来执行您需要的操作(仅此而已)并使用适当类型的后备存储。

类似这样的:

class MyTransactions
{
  private DateTime? OldestDate   { get ; set ; }
  private Dictionary<DateTime,List<Transaction>> BackingStore { get ; set ; }
  private int RetentionPeriodInDays
  {
    get
    {
      DateTime now     = DateTime.Now.Date ;
      TimeSpan oneYear = now - now.AddYears(-1) ;
      int      days    = (int) oneYear.TotalDays ;
      return days ;
    }
  }

  public MyTransactions()
  {
    OldestDate = null ;
    BackingStore = new Dictionary<DateTime,List<Transaction>>();
  }

  public void Add( Transaction t )
  {
    if ( t == null ) throw new ArgumentNullException("t");

    if ( this.BackingStore.Count > RetentionPeriodInDays )
    {
      this.BackingStore.Remove(this.OldestDate.Value ) ;
      this.OldestDate = this.BackingStore.Keys.Min() ;
    }

    DateTime today = DateTime.Now.Date ;
    List<Transaction> transactions ;
    bool exists = this.BackingStore.TryGetValue(today,out transactions) ;
    if ( !exists )
    {
      transactions = new List<Transaction>();
      this.BackingStore.Add(today,transactions) ;
    }
    transactions.Add(t) ;

    if ( today < this.OldestDate )
    {
      this.OldestDate = today ;
    }

    return ;
  }

  public List<Transaction> TodaysData
  {
    get
    {
      DateTime today = DateTime.Now.Date ;
      List<Transaction> value = new List<Transaction>( this.BackingStore[today] ) ;
      return value ;
    }
  }

  public List<Transaction> CurrentWeekData
  {
    get
    {
      DateTime today = DateTime.Now.Date ;
      List<Transaction> value = this.BackingStore
                                    .Where( x => x.Key > today.AddDays(-7) )
                                    .SelectMany( x => x.Value )
                                    .ToList()
                                    ;
      return value ;
    }
  }

}

【讨论】:

    【解决方案4】:

    这是一个跟踪在特定时期内添加到其中的元素的类。要使用它:

        // creating
        var q = new RecentQueue<Transaction>(TimeSpan.FromDays(360)); // last 360 days
        var q = new RecentQueue<Transaction>(TimeSpan.FromSeconds(5)) // last 5 seconds
    
        // adding elements
        var t = new Transaction { Category = "cat1", TotalCost = "5",
                                    TotalEarned = "3", TotalHST = "2" }
        q.Enqueue(t);
    
        // iterating 
        foreach (var element in q)
            // do whatever
    

    代码:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace MyCollections
    {
        public class RecentQueue<T> : IEnumerable<T>
        {
            class RecentItem<U>
            {
                public U Item { get; set; }
                public DateTime Date { get; set; }
            }
    
            public TimeSpan Period { get; set; }
            private Queue<RecentItem<T>> _q;
    
            public RecentQueue(TimeSpan t)
            {
                Period = t;
                _q = new Queue<RecentItem<T>>();
            }
    
            public void Enqueue(T t)
            {
                Enqueue(t, DateTime.Now);
            }
    
            public void Enqueue(T t, DateTime date)
            {
                Cut();
                _q.Enqueue(new RecentItem<T> { Date = date, Item = t });
            }
    
            public IEnumerator<T> GetEnumerator()
            {
                Cut();
                foreach (var element in _q)
                    yield return element.Item;
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                Cut();
                foreach (var element in _q)
                    yield return element.Item;    
            }
    
            private void Cut()
            {
                var date = DateTime.Now;
                while (_q.Count > 0 && date - _q.Peek().Date > Period)
                    _q.Dequeue();
            }
        }
    }
    

    但是,我同意 couchand 的观点,“真正的”解决方案不是这个,也不是任何其他内存数据结构。它只是使用数据库,在日期上对其进行索引并进行查询。

    我发布的课程实际上对于一些在短时间内(最后几秒钟等)跟踪快速发生事件的应用程序更有用,因为这样你就不想用请求打击数据库,你想要高性能,而且您不关心保存数据。

    如果您要跟踪 360 天的数据,您需要一个数据库。

    【讨论】:

      【解决方案5】:

      如果您要采用“每天一个时段”的方法,一个选项是二维数组。一个长度为 365 的数组,该数组中的每个插槽都有自己的数组或列表结构来跟踪当天的交易。

      如何保存?我会使用 XML,但这只是个人喜好,因为我在 C# 中序列化和反序列化 XML 方面有很多经验。

      或者正如另一个答案所说,数据库非常适合您在结构方面寻找的内容。取决于这个项目的规模。

      编辑:将答案从哈希表更改为二维数组。

      【讨论】:

      • 哈希表不允许每个插槽允许多个条目;您需要将表的值设为一个集合。接下来,当您要添加新项目时,没有简单的方法可以找到“最旧的日期”以将其从集合中删除;你必须做一个线性搜索。这根本不是一个非常适合这个问题的结构。
      • 啊,谢谢。当我想到“哈希表”时,我意识到了我的意思——我会更新我的答案。
      • 另外,实际的HashTable 类已贬值,您应该使用Dictionary
      • 哦,好的。当我说 HashTable 时,我实际上并没有尝试引用 C# 类型,而只是结构背后的想法。不过,下次我需要使用时,我会记住这一点。
      猜你喜欢
      • 1970-01-01
      • 2010-11-21
      • 2015-02-13
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多