我有2个或更多的动态字符串数组,填充了一些巨大的数据,我想将这个2数组合并到一个数组,我知道我可以用这样的for循环来做:
var
Arr1, Arr2, MergedArr: Array of string;
I: Integer;
begin
// Arr1:= 5000000 records
// Arr2:= 5000000 records
// Fill MergedArr by Arr1
MergedArr:= Arr1;
// Set length of MergedArr to length of ( Arra1 + Arr2 )+ 2
SetLength(MergedArr, High(Arr1)+ High(Arr2)+2);
// Add Arr2 to MergedArr
for I := Low(Arr2)+1 to High(Arr2)+1 do
MergedArr[High(Arr1)+ i]:= Arr2[i-1];
end;
但是对于庞大的数据来说速度很慢,复制阵列内存数据有更快的方法吗?
答案 0 :(得分:8)
首先string
是特殊的,所以应该特别对待它:不要试图超越编译器,保持代码不变。字符串是特殊的,因为它的引用计数。每次将字符串从一个地方复制到另一个地方时,它的引用计数会递增。当引用计数达到0时,字符串将被销毁。你的代码很好用,因为它让编译器知道你在做什么,反过来编译器有机会正确地增加所有引用计数。
当然,你可以按照gabr答案的评论中的建议玩各种技巧,比如用零填充旧数组,这样新数组中的引用计数仍然有效,但如果你确实需要,你就不能这样做旧阵列也是如此。这有点像黑客(虽然可能在可预见的未来有效)。 (并且需要注意的是,我实际上喜欢这个黑客)。
无论如何,这是我答案的重要部分,你的代码很可能在将字符串从一个数组复制到另一个数组时速度慢,而且很可能在其他地方慢慢地。这是一个简短的控制台应用程序,它创建两个数组,每个数组有5M随机字符串,然后将两个数组合并为第三个,并显示创建合并所花费的时间。 合并在我的计算机上只需要大约300毫秒。填充阵列需要更长的时间,但我没有计时:
程序Project26;
{$APPTYPE CONSOLE}
uses SysUtils, Windows;
var a, b, c: array of string;
i: Integer;
Freq: Int64;
Start, Stop: Int64;
Ticks: Cardinal;
const count = 5000000;
begin
SetLength(a,count);
SetLength(b,count);
for i:=0 to count-1 do
begin
a[i] := IntToStr(Random(1));
b[i] := IntToStr(Random(1));
end;
WriteLn('Moving');
QueryPerformanceFrequency(Freq);
QueryPerformanceCounter(Start);
SetLength(c, Length(a) + Length(b));
for i:=0 to High(a) do
c[i] := a[i];
for i:=0 to High(b) do
c[i+Length(a)] := b[i];
QueryPerformanceCounter(Stop);
WriteLn((Stop - Start) div (Freq div 1000), ' milliseconds');
ReadLn;
end.
答案 1 :(得分:7)
您可以使用内置的Move功能将内存块移动到另一个位置。参数是源和目标内存块以及要移动的数据大小。
因为要复制字符串,所以必须在合并后通过用零填充来销毁源数组。否则,对于字符串的重新计算将是错误的,从而导致程序中的破坏和破坏。
var
Arr1, Arr2, MergedArr: Array of string;
I: Integer;
begin
SetLength(Arr1, 5000000);
for I := Low(Arr1) to High(Arr1) do
Arr1[I] := IntToStr(I);
SetLength(Arr2, 5000000);
for I := Low(Arr2) to High(Arr2) do
Arr2[I] := IntToStr(I);
// Set length of MergedArr to length of ( Arra1 + Arr2 )+ 2
SetLength(MergedArr, High(Arr1)+ High(Arr2)+2);
// Add Arr1 to MergedArr
Move(Arr1[Low(Arr1)], MergedArr[Low(MergedArr)], Length(Arr1)*SizeOf(Arr1[0]));
// Add Arr2 to MergedArr
Move(Arr2[Low(Arr2)], MergedArr[High(Arr1)+1], Length(Arr2)*SizeOf(Arr2[0]));
// Cleanup Arr1 and Arr2 without touching string refcount.
FillChar(Arr1[Low(Arr1)], Length(Arr1)*SizeOf(Arr1[0]), 0);
FillChar(Arr2[Low(Arr2)], Length(Arr2)*SizeOf(Arr2[0]), 0);
// Test
for I := Low(Arr1) to High(Arr1) do begin
Assert(MergedArr[I] = IntToStr(I));
Assert(MergedArr[I] = MergedArr[Length(Arr1) + I]);
end;
// Clear the array to see if something is wrong with refcounts
for I := Low(MergedArr) to High(MergedArr) do
MergedArr[I] := '';
end;
答案 2 :(得分:3)
一个优秀的格言是最快的代码是永不运行的代码。由于复制费用昂贵,因此您应该避免复制费用。
您可以使用虚拟阵列执行此操作。创建一个包含array of string
数组的类。在您的示例中,外部数组将包含两个字符串数组。
Count
属性,该属性返回所有数组中的字符串总数。