筆者最近寫了一個監(jiān)控軟件, 數(shù)據(jù)量較大, 而所用插件刷新有壓力. 所以就寫了一個支持?jǐn)?shù)據(jù)抽取的大數(shù)據(jù)維護(hù)類.
// 設(shè)計需求:
// 會發(fā)生數(shù)據(jù)的新增, 并且在數(shù)據(jù)達(dá)到上限時自動去掉前半截數(shù)據(jù),
// 高頻的等間隔讀取抽有數(shù)據(jù),
// 數(shù)據(jù)結(jié)構(gòu)大小是可以在生成對象時提供, 并且對不提供大小參數(shù)的情況下使用默認(rèn)大小
// 數(shù)據(jù)量較大(大約有40萬個元素),
// 支持等距提取若干個數(shù)據(jù),
// 比如從最后20000個樹種提取2000個數(shù)據(jù)(可通過參數(shù)設(shè)置這個數(shù)量),
// 提取的規(guī)則是:返回提取的數(shù)據(jù)量, 將提取的數(shù)寫入到調(diào)用者提供的list中
// 設(shè)計思路:
// 使用List<T> 或LinkedList<T>都有一些弊端:
// List<T> 在去除數(shù)據(jù)時,需要將后半部分的數(shù)據(jù)移動到前面,對于大數(shù)據(jù)量來說,性能開銷較大。
// LinkedList<T> 在隨機(jī)訪問數(shù)據(jù)時,效率較低,因為需要從頭開始遍歷到目標(biāo)位置。
// 在C#中,沒有現(xiàn)成的數(shù)據(jù)結(jié)構(gòu)可以同時滿足這些需求。因此,自己設(shè)計一個數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)這些功能。
// 將兩個List<T>結(jié)合使用,每個List<T>存儲一半的數(shù)據(jù)。當(dāng)數(shù)據(jù)達(dá)到上限時,丟棄第一個List<T>,并創(chuàng)建一個新的List<T>來存儲新的數(shù)據(jù)。
public interface IDataExtractor<T>
{
(int startIndex, double interval) ExtractDataFromEnd(int lastCount, int extractCount, List<T> targetList);
}
public class LargeDataStructure<T> : IDataExtractor<T>
{
private const int DefaultHalfMaxRecordsNum = 60 * 60 * 24 * 7 * 2; // Default half of max records
private int halfMaxRecordsNum;
private List<T> firstHalf;
private List<T> secondHalf;
public int AllDataCount => firstHalf.Count + secondHalf.Count;
public LargeDataStructure(int? maxRecordsNum = null)
{
this.halfMaxRecordsNum = (maxRecordsNum ?? DefaultHalfMaxRecordsNum) / 2;
this.firstHalf = new List<T>(halfMaxRecordsNum);
this.secondHalf = new List<T>(halfMaxRecordsNum);
}
public void Append(T data)
{
if (secondHalf.Count >= halfMaxRecordsNum)
{
// Discard the first half and move the second half to the first
firstHalf = secondHalf;
secondHalf = new List<T>(halfMaxRecordsNum);
}
if (firstHalf.Count < halfMaxRecordsNum)
{
firstHalf.Add(data);
}
else
{
secondHalf.Add(data);
}
}
public T this[int index] // indexer
{
get
{
if (index < halfMaxRecordsNum)
{
return firstHalf[index];
}
else
{
return secondHalf[index - halfMaxRecordsNum];
}
}
}
public (int, double) ExtractDataFromEnd(int lastCount, int extractCount, List<T> targetList)
{
targetList.Clear();
int startIndex = Math.Max(0, AllDataCount - lastCount);
int validCount = AllDataCount - startIndex;
double interval = 1;
if (extractCount >= validCount)
{
// 提取的數(shù)量大于等于最后的數(shù)據(jù)量
for (int i = startIndex; i < AllDataCount; i++)
{
targetList.Add(this[i]);
}
}
else
{
interval = (double)(validCount-1) / (extractCount - 1); // 計算浮點數(shù)等距間隔
for (int i = 0; i < extractCount; i++)
{
int index = (int)Math.Round(startIndex + interval * i);
index = Math.Min(index, AllDataCount - 1); // 確保不超過數(shù)據(jù)范圍
targetList.Add(this[index]);
}
}
return (startIndex, interval);
}
}
private void TestExtractDataFromEnd()
{
LargeDataStructure<int> dataStructure = new LargeDataStructure<int>();
// 添加一些數(shù)據(jù)用于測試
for (int i = 0; i < 20; i++)
{
dataStructure.Append(i);
}
List<int> result = new List<int>();
// 用例1.測試數(shù)據(jù)量不足,提取 30 個數(shù)據(jù)
dataStructure.ExtractDataFromEnd(50, 30, result);
Console.WriteLine("數(shù)據(jù)量不足,提取 30 個數(shù)據(jù):");
foreach (int data in result)
{
Console.Write(data + " ");
}
Console.WriteLine();
// 再添加一些數(shù)據(jù)用于測試
for (int i = 20; i < 100; i++)
{
dataStructure.Append(i);
}
// 用例2.測試整數(shù)等距提取,提取 5 個數(shù)據(jù)
dataStructure.ExtractDataFromEnd(10, 5, result);
Console.WriteLine("整數(shù)等距提取(10個數(shù)據(jù)中提取5個):");
foreach (int data in result)
{
Console.Write(data + " ");
}
Console.WriteLine();
// 用例3.測試浮點數(shù)等距提取,提取 20 個數(shù)據(jù)
dataStructure.ExtractDataFromEnd(30, 20, result);
Console.WriteLine("浮點數(shù)等距提?。?0個數(shù)據(jù)中提取20個):");
foreach (int data in result)
{
Console.Write(data + " ");
}
Console.WriteLine();
// 用例4.測試尾部數(shù)超過需求數(shù), 想從5個數(shù)中提取100個(不合法參數(shù)
dataStructure.ExtractDataFromEnd(5, 100, result);
Console.WriteLine("尾部數(shù)超過需求數(shù)(5個數(shù)據(jù)中提取100個):");
foreach (int data in result)
{
Console.Write(data + " ");
}
Console.WriteLine();
Console.ReadLine();
}
當(dāng)涉及處理大量數(shù)據(jù)時,LargeDataStructure類可以作為一個有用的工具。
該類可以存儲大量數(shù)據(jù),并提供了一些功能來操作和提取這些數(shù)據(jù)。以下是LargeDataStructure類的總結(jié):
-
LargeDataStructure類的目的是處理大量數(shù)據(jù),它被設(shè)計為實現(xiàn)IDataExtractor接口。
-
LargeDataStructure類內(nèi)部使用兩個List<int>對象(firstHalf和secondHalf)來存儲數(shù)據(jù)。這兩個列表分別表示數(shù)據(jù)的前半部分和后半部分。
-
構(gòu)造函數(shù)LargeDataStructure(int? maxRecordsNum = null)允許你創(chuàng)建一個LargeDataStructure對象,并可選地指定最大記錄數(shù)(maxRecordsNum)。如果未提供最大記錄數(shù),將使用默認(rèn)值。
-
方法Append(int data)用于將數(shù)據(jù)添加到LargeDataStructure對象中。如果secondHalf列表的大小達(dá)到最大記錄數(shù)的一半(halfMaxRecordsNum),則會丟棄firstHalf列表中的數(shù)據(jù),并將secondHalf作為新的firstHalf。然后,創(chuàng)建一個新的空的secondHalf列表來接收后續(xù)的數(shù)據(jù)。
-
LargeDataStructure類還提供了索引器(this[int index]),允許你通過索引訪問LargeDataStructure對象中的數(shù)據(jù)。該索引器考慮了數(shù)據(jù)的分布,以正確地獲取指定索引位置的數(shù)據(jù)。
-
方法ExtractDataFromEnd(int lastCount, int extractCount, List<int> targetList)允許你從LargeDataStructure對象的末尾提取指定數(shù)量的數(shù)據(jù)。你可以指定最后的數(shù)據(jù)數(shù)量(lastCount),要提取的數(shù)據(jù)數(shù)量(extractCount)以及目標(biāo)列表(targetList)來接收提取的數(shù)據(jù)。
-
如果提取的數(shù)量大于等于最后的數(shù)據(jù)數(shù)量,ExtractDataFromEnd方法將提取所有最后的數(shù)據(jù)。否則,它將根據(jù)浮點數(shù)等距間隔從數(shù)據(jù)中提取相應(yīng)數(shù)量的數(shù)據(jù)。在計算浮點數(shù)等距間隔時,會考慮有效數(shù)據(jù)的數(shù)量,以確保提取不超過數(shù)據(jù)的范圍。文章來源:http://www.zghlxwxcb.cn/news/detail-490979.html
LargeDataStructure類提供了一種高效且靈活的方式來處理大量數(shù)據(jù),并具有數(shù)據(jù)添加、數(shù)據(jù)訪問以及從數(shù)據(jù)末尾提取數(shù)據(jù)的功能。這個類可以根據(jù)你的需求進(jìn)行進(jìn)一步的擴(kuò)展和定制。文章來源地址http://www.zghlxwxcb.cn/news/detail-490979.html
到了這里,關(guān)于C#當(dāng)動態(tài)數(shù)據(jù)過大畫圖有困難時怎么辦?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!