1行読み込んである変数を基準にしたソートのコードを教えてください

解決


ようこ  2002-10-10 22:56:43  No: 1671

FILE1.TXTの内容
  A     B      C    D    E    F
①ax  101abc  x10  x20  y10  y20
②ax  235abc  x11  x21  y11  y21
③ax  098acd  x12  x22  y12  y22
④ax  125bac  x13  x23  y13  y23
⑤ax  215abc  x14  x24  y14  y24
⑥ax  487abj  x15  x25  y15  y25
⑦ax  894akc  x16  x26  y16  y26
⑧ax  236bcg  x17  x27  y17  y27
            ;
            ;
EOF

FILE2.TXTの内容
  A     B      C    D    E    F
③ax  098acd  x12  x22  y12  y22
①ax  101abc  x10  x20  y10  y20
④ax  125bac  x13  x23  y13  y23
⑤ax  215abc  x14  x24  y14  y24
②ax  235abc  x11  x21  y11  y21
⑧ax  236bcg  x17  x27  y17  y27
⑥ax  487abj  x15  x25  y15  y25
⑦ax  894akc  x16  x26  y16  y26
            ;
            ;
EOF

FILE1.TXTの内容を初めからEOFまで1行づつ読み込んで
Bの文字列を基準にしてファイル内の各行をソートし、
新規ファイルFILE2.TXTへ書き込んで終了するコードを教えてさい。
できればオーソドックスな方法とTStringClassを使った方法の
2通りでお願い致します。


aiko  2002-10-10 23:15:12  No: 1672

①とかはわかりやすくするために表示してあるだけですよね?

だとしたらソートすればいいと思いますけど

var
  str:TStringList;
begin
  str:=TStringList.Create;
  str.LoadFromFile('FILE1.TXT');
  str.Sort;
  str.SaveToFile('FILE2.TXT');
  str.Free;
end;
こういうことじゃないですか?
間違ってたらすみません。


ようこ  2002-10-11 20:33:59  No: 1673

申し訳ないです。
以下のファイル内容の間違いでした。
おっしゃる通り①とはファイル内に無いです。
Classを使わないコードとClassを使うコードを
ソートを理解したいので改めて教えて頂けないでしょうか?

FILE1.TXTの内容
  A     B      C    D    E    F
①fx  101abc  x10  x20  y10  y20
②cx  235abc  x11  x21  y11  y21
③ax  098acd  x12  x22  y12  y22
④bx  125bac  x13  x23  y13  y23
⑤ax  215abc  x14  x24  y14  y24
⑥ax  487abj  x15  x25  y15  y25
⑦dx  894akc  x16  x26  y16  y26
⑧ax  236bcg  x17  x27  y17  y27
            ;
            ;
EOF

FILE2.TXTの内容
  A     B      C    D    E    F
③ax  098acd  x12  x22  y12  y22
①fx  101abc  x10  x20  y10  y20
④bx  125bac  x13  x23  y13  y23
⑤ax  215abc  x14  x24  y14  y24
②cx  235abc  x11  x21  y11  y21
⑧ax  236bcg  x17  x27  y17  y27
⑥ax  487abj  x15  x25  y15  y25
⑦dx  894akc  x16  x26  y16  y26
            ;
            ;
EOF


hatena  2002-10-12 01:48:54  No: 1674

TStringList の CustomSort を使えば、簡単にできすます。

function MySort(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := CompareStr(Copy(List[Index1], 5, 6), Copy(List[Index2], 5, 6));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  str:TStringList;
begin
  str:=TStringList.Create;
  str.LoadFromFile('FILE1.TXT');
  str.CustomSort(MySort);
  str.SaveToFile('FILE2.TXT');
  str.Free;
end;

1行目の
  A     B      C    D    E    F
や、最後の、
EOF
という行があるのなら先に削除してからソートしてください。

>Classを使わないコード

とは、TList、TFileStream 等のクラスも使わないでということですか。


ようこ  2002-10-15 17:35:51  No: 1675

TStringList の CustomSortはいろいろ調べたんですが、便利なものがDelphiには、用意されているんですね。
Classを使わないコードとは、標準入出力やソート部を自分で作成する事です。


hatena  2002-10-16 11:54:23  No: 1676

TStringList を使わないとすると、固定長データなので、
1行をRecord型の変数に格納するのが常套手段でしょう。
全体のデータの格納先としては、TList か 動的配列 か、になります。
TList は、Sortメソッドを持ってますので、ソートは楽ですが、
ポインタとして扱わなければならないので、インスタンスを作成したり、
解放したりしなければなりません。

どちらも一長一短ですが、
今回のリクエストはソート部は自分でということなので、
動的配列を使ってみました。

標準入出力で、とういうことでしたが、TFileStream にしました。
操作としてはほとんど同じですか、標準入出力では、排他制御が
できませんので、安全性を考慮して TFileStream にしました。

ソートはクイックソートを使いました。TListやTStringListと
同じ手法の比較関数でソートの定義をする手法を使ってます
(やはり使いやすいので)。

ちょっと長くなりますが、ご容赦ください。

unit Unit1;

interface

uses
  Windows, Controls, StdCtrls, Classes, Forms, SysUtils;

type
  TMyRec = Packed Record
    A: Array[1..4] of Char;
    B: Array[1..6] of Char;
    C: Array[1..5] of Char;
    D: Array[1..5] of Char;
    E: Array[1..5] of Char;
    F: Array[1..5] of Char;
    CrLf: Array[1..2] of Char;
  end;
  TMyRecArray = array of TMyRec;

  TArraySortCompare = function (Item1, Item2: TMyRec): Integer;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FRecArray: TMyRecArray;
    procedure DataLoadFromFile(const FileName: string);
    procedure DataSaveToFile(const FileName: string);
    procedure DataSort(Compare: TArraySortCompare);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.DataLoadFromFile(const FileName: string);
var
  FFile:TFileStream;
  Len: integer;
begin
  FFile := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
  try
    Len := FFile.Size div SizeOf(TMyRec);
    SetLength(FRecArray, Len);
    FFile.Read(FRecArray[0], SizeOf(TMyRec) * Len);
  finally
    FFile.Free;
  end;
end;

procedure TForm1.DataSaveToFile(const FileName: string);
var
  FFile:TFileStream;
  Len: integer;
begin
  FFile := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
  try
    Len := SizeOf(TMyRec) * Length(FRecArray);
    FFile.Write(FRecArray[0], Len);
  finally
    FFile.Free;
  end;
end;

procedure QuickSort(SorTArray: TMyRecArray; L, R: Integer;
  SCompare: TArraySortCompare);
var
  I, J: Integer;
  P, T: TMyRec;
begin
  repeat
    I := L;
    J := R;
    P := SorTArray[(L + R) shr 1];
    repeat
      while SCompare(SorTArray[I], P) < 0 do Inc(I);
      while SCompare(SorTArray[J], P) > 0 do Dec(J);
      if I <= J then
      begin
        T := SorTArray[I];
        SorTArray[I] := SorTArray[J];
        SorTArray[J] := T;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then QuickSort(SorTArray, L, J, SCompare);
    L := I;
  until I >= R;
end;

procedure TForm1.DataSort(Compare: TArraySortCompare);
var
  Len: Integer;
begin
  Len := Length(FRecArray);
  if Assigned(Compare) and (FRecArray <> nil) and (Len > 0) then
    QuickSort(FRecArray, 0, Len - 1, Compare);
end;

function MyCompare(Item1, Item2: TMyRec): Integer;
begin
  Result := CompareStr(Item1.B, Item2.B);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  DataLoadFromFile('FILE1.TXT');
  DataSort(MyComPare);
  DataSaveToFile('FILE2.TXT');
end;

end.

1行目に
  A     B      C    D    E    F
がある場合は、これを読み飛ばす処理を追加する必要があります。


hatena  2002-10-16 11:59:09  No: 1677

訂正です。

最後の方の、
procedure TForm1.Button3Click(Sender: TObject);
の部分は、
procedure TForm1.Button1Click(Sender: TObject);
にしてください。


ようこ  2002-10-16 17:31:25  No: 1678

hatenaさん、長いコードまで教授頂き有り難う御座いました。
大変、理解に役立ちました。
m(_ _)m!


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加