我正在尝试在过去的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笔交易。我的程序使用纯文本文件作为外部存储,但我如何加载它取决于我决定如何存储这些数据。
最好的方法是什么?
答案 0 :(得分:2)
我不确定队列是否正是您在这里寻找的。队列是一种短暂的数据结构:它不是为了让事物保持一段时间,而且它当然不是为了让你按照自己想要的方式对数据进行切片和切块。
听起来你的用例正在为数据库而烦恼。长期存储结构化数据的目的是按各种标准进行排序或查询,这正是数据库的发明。
答案 1 :(得分:0)
你显然是在方便而不是速度之后。您期望商店的典型用法总共约5400笔交易。这真的很小,一个ArrayList
应该没问题。当您想要查询数据时,只需遍历它,将相关项添加到另一个ArrayList
并返回。
只需按顺序保存数据 - 即所有新事务都会被推到列表的后面。如果你想按类别提取,那就应该像白天一样简单。
保持单个结构并将查询复制出来将使您的生活更轻松,特别是如果您的类在多个线程中使用并需要锁定。
对我而言,维护索引以加快查找速度或使用数据库似乎有些过分。如果一个简单的解决方案运行良好,那么使用它。它更容易维护,更不容易出错。
答案 2 :(得分: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,&#34; real&#34;解决方案不是这个,或任何其他内存数据结构。它只是使用数据库,在日期上对其进行索引并查询它。
我发布的课程实际上对于在短时间内(最后几秒钟等)跟踪快速发生的事件的应用程序更有用,因为那时你不想用请求来打击数据库,你想要高性能,而不必关心保存数据。
如果您要追踪360天的数据,那么您需要一个数据库。
答案 3 :(得分: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 ;
}
}
}
答案 4 :(得分:-1)
如果您打算采用“每天一个插槽”的方法,那么一个选项就是二维数组。数组365的长度,该数组中的每个插槽都有自己的数组或列表结构,以跟踪当天的事务。
如何存放?我会使用XML,但这只是个人偏好,因为我在C#中序列化和反序列化XML方面有很多经验。
或者正如另一个答案所说,数据库非常适合您在结构方面寻找的东西。取决于该项目的规模。
编辑:将答案从哈希表更改为二维数组。