2012-10-17 28 views
1

早上好。扣除,直到達到期望值

我目前正在努力弄清楚我有信心的事情很簡單,但事實證明,這是一項任務,實際工作中的一半。

我正在設計一個項目,旨在通過在別處重新放置各種文件來最大程度地降低驅動器使用率。我有一個數組(0..12)int64值包含我可能想要移動的文件的文件大小。該陣列按預測最大文件大小預測最小文件大小的方式排序。我還獲得了存儲在不同陣列中的這些文件的名稱(稱爲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]_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行),但這樣既維持混亂又不理想。我很想看看它是如何在一個循環中完成的。我通常不會遇到迴路問題,但這對我來說並不是一個標準問題。

+1

聽起來你正在研究解決[bin-packing問題](http://en.wikipedia.org/wiki/Bin_packing_problem)以使文件適合最少數量的安裝介質。示例近似實現在線和常用算法教科書中都很常見。這是一個NP難題,但只有13個文件,運行時間不應該太差。 –

回答

1
curdiff:= 0; 
i:= Low(_WoWDataFileSize) - 1; 
while (curdiff <= reqsize) and (i < High(_WoWDataFileSize)) do 
begin 
    inc (i); 
    curdiff:= curdiff + _WoWDataFileSize[i]; 
end; 

在循環結束時,您已達到所需的縮小大小或迭代了整個數組。

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和列表(感謝名單仿製藥),這將是非常簡單的:

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; 
+0

對於你的'Break'陳述,你從'repeat','until'字中感受到了什麼?另外,還有'repeat/until'循環跟着'for'循環;試着去思考一下,當你使用'Break'語句時,是否僅僅使用其中的一個。 – TLama

+0

@TLama是的,你是對的:o)但是根本不清楚,這個結果將如何幫助決定應該複製哪些文件 –

0

感謝大家對自己的答案,我想通了,我要去哪裏錯了。當我在最初的問題中進行計算時,我忘記了解決數值上的劃分(爲了顯示MB而不是字節,因爲TBWoWDir.Value已活動到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在開發過程中,我需要驗證一個值是否正確返回,因爲我確定許多其他人也這樣做)。