1

大家早上好。

我目前正在尝试找出一些我相信它足够简单但被证明是一项任务半才能真正解决的问题。

我正在开发一个项目,旨在通过将各种文件重新定位到其他地方来最大限度地减少驱动器的使用。我有一个int64值数组(0..12),其中包含我可能想要移动的文件的文件大小。数组的排序方式是预测的最大文件大小到预测的最小文件大小。我还将这些文件的名称存储在不同的数组中(称为WoWData, 也[0..12])。然后我得到了“安装尺寸”和“所需尺寸”。

我的任务是计算我需要移动哪些文件,以便通过遍历文件大小数组将“安装大小”降低到“所需大小”,并将值从安装大小中取出,直到我达到 <=所需的大小。

这是我一直在尝试使用的一些示例代码(Delphi/Firemonkey)。试图弄清楚如何完成这样的任务让我感到困惑,因此毫无疑问会有很多问题;

Global Vars;
    _WoWDataFileSize : Array [0..12] of Int64;
    // "TBWoWDir" is a TTrackBar (Firemonkey)

var
  TotalSize, ReqSize, DiffSize, CurDiff : Int64;
  i : Integer;
begin
  // Set up initial values to work with
  ReqSize := Round(TBWoWDir.Value); // Requested Size
  TotalSize := Round(TBWoWDir.Max); // Actual installation size
  CurDiff := 0; // Assume as "Current Difference in size"

  // Calculate difference between install and requested size
  DiffSize := TotalSize - ReqSize; // This calculates correctly

// The below is what i'm struggling with
  repeat
    for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
      begin
        CurDiff := ReqSize - _WoWDataFileSize[i];
      end;
  until CurDiff <= ReqSize;
end;

我确实尝试过只使用一个repeat .. until没有循环的for循环,但同样,我在试图弄清楚它时变得太困惑了。


让我举个例子。让我们假设它_WoWDataFileSize[0]是 200,并且_WoWDataFileSize[1]通过 to_WoWDataFileSize[12]与它们的数组索引的值相同(例如_WoWDataFileSize[6]= 6、_WoWDataFileSize[8]= 8 等)。

如果我想计算 150 的值(这将是200 - 12 - 11 - 10 - 9 - 8,或Array[0] - Array[12] - Array[11] - Array[10] - Array[9] - Array[8]根据数组),并从数组中获取我需要移动以满足此要求的文件列表,我将WoWData如何编写例程?

150 可以替换为任何数字,因为我正在努力实现由TBWoWDir.Value.

我在想我可能需要做一个While循环并使用i := i+1设置。实际上,我可以通过并对其进行硬编码,以便一次取出数组中的一个值,并每次检查我是否 <= 所需的值——每个项目有 2-3 行(所以总共 24-36 行),但这既难以维护又不是最佳的。我有兴趣看看它是如何在循环中完成的。我通常不会遇到循环问题,但这对我来说几乎不是标准的。

4

3 回答 3

1

恕我直言,您的代码中仅缺少两行:o)

CurDiff := ReqSize;
// repeat
  for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
    begin
      CurDiff := CurrDiff - _WoWDataFileSize[i];
      if CurDiff <= ReqSize then break; // breaks the for..to loop
    end;
// until CurDiff <= ReqSize;

编辑不需要重复...直到循环

但是恕我直言,仅计算大小而不存储匹配的文件并不是很有用。因此,使用 CustomObject 和 Lists(感谢泛型)将非常简单:

type
  TFileObject = class
  private
    FName : string;
    FSize : Int64;
  public
    constructor Create( AName : string; ASize : Int64 );
  published
    property Name : string read FName;
    property Size : Int64 read FSize;
  end;

procedure MoveFileObject(AMaxSize : Int64; ASrcList, ATarList : TList<TFileObject> );
var
  LItem : TFileObject;
  LSize : Int64;
begin
  LSize := 0;
  for LItem in ASrcList do
  begin
    if LSize + LItem.Size <= AMaxSize then
      begin
        LSize := LSize + LItem.Size;
        ATarList.Add( LItem );
      end;
  end;
end;
于 2012-10-17T06:37:21.010 回答
1
curdiff:= 0;
i:= Low(_WoWDataFileSize) - 1;
while (curdiff <= reqsize) and (i < High(_WoWDataFileSize)) do
 begin
  inc (i);
  curdiff:= curdiff + _WoWDataFileSize[i];
 end;

在循环结束时,要么你已经达到了所需的大小减少,要么你已经遍历了整个数组。

于 2012-10-17T06:08:16.490 回答
0

感谢大家的回答,我知道我哪里错了。当我在最初的问题中进行计算时,我忘记考虑我对值的划分(为了显示 MB 而不是 Bytes 与TBWoWDir.Valuea 绑定TLabel.text,但实际大小在分配之前被划分TBWoWDir.Max)。

感谢 No'am Newman 的回答中的一些调整,我设法自己解决了这个问题。这就是我如何得到我想要的结果(或者更接近它);

Global Vars;
    _WoWDataFileSize : Array [0..12] of Int64;
Global Const;
    _WoWData : Array [0..12] of String;
    // "TBWoWDir" is a TTrackBar (Firemonkey)

[...]
var
  ReqSize : int64;
  DiffSize, CurDiff : Int64;
  i, ii : Integer;
  FilesTot : Integer;
  FILESMSG : String;
begin
  // Set up initial values to work with
  ReqSize := Round(TBWoWDir.Value) * 1024 * 1024; // Requested Size - Multiplied from formatting
  TotalSize := Round(TBWoWDir.Max) * 1024 * 1024; // Actual installation size - Multiplied from formatting

  DiffSize := TotalSize - ReqSize; // Calculate Difference
  CurDiff := 0; // Reset Current Difference
  i := -1; // Reset i
  repeat
    inc (i); // Increment i
    CurDiff := CurDiff + _WoWDataFileSize[i]; // Add current array item file size to CurDiff
  until (CurDiff >= (DiffSize)) or (i >= 12); // Repeat until we reach ideal size or the end of the array

  // Calculate which array item we stopped at
  for ii := 0 to i do // use i from previous loop as the max
  begin
    FILESMSG := FILESMSG + 'File: ' + WoWData[ii] +
                           ' | Size: ' + IntToStr(_WoWDataFileSize[ii])+' '#13#10;
    FilesTot := FilesTot + _WoWDataFileSize[ii];
  end;

  // Show Message providing details
  ShowMessage('CurDiff:' + IntToStr(CurDiff div 1024 div 1024) +
              ' | DiffSize: ' + IntToStr(DiffSize div 1024 div 1024) +
              ' | Array i: ' +
              IntToStr(i) +#13#10+
              'Difference between CurDiff and DiffSize: '+ IntToStr(((DiffSize div 1024 div 1024) - (CurDiff div 1024 div 1024)))+#13#10#13#10+
              'File Details' +#13#10#13#10+
              FilesMsg +#13#10#13#10+
              'Total Size: ' + IntToStr(FilesTot));
end;

那里的代码告诉我需要复制哪些文件(因此现在修改它以复制文件并不太难),并且整个代码ShowMessage用于自我证明(ShowMessage当我需要验证时在开发过程中使用值正确返回,我相信许多其他人也会这样做)。

于 2012-10-17T17:31:17.593 回答