-1

我正在尝试将过去 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 笔交易。我的程序使用纯文本文件作为外部存储,但我如何加载它取决于我决定如何存储这些数据。

最好的方法是什么?

4

5 回答 5

2

我不确定队列是否正是您在这里寻找的。队列是一种短暂的数据结构:它的目的不是让事物保持一段时间,而且它当然不是为了让您以您想要的方式对数据进行切片和切块。

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

于 2013-10-23T20:37:43.533 回答
0

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

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

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

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

于 2013-10-23T20:44:56.077 回答
0

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

    // 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 天的数据,您需要一个数据库。

于 2013-10-23T21:35:18.773 回答
0

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

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

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

像这样的东西:

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 ;
    }
  }

}
于 2013-10-23T21:54:23.343 回答
-1

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

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

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

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

于 2013-10-23T20:47:32.997 回答