0

並べ替えを適用しながら、2 つのファイルをマージする必要があります。メモリ使用量のタスクを軽くしておくことが重要です。これには、c# でコンソール アプリを作成する必要があります。

入力ファイル 1:

一部のヘッダー
A12345334
A00123445
A44566555
B55677
B55683
B66489
レコード数: 6

入力ファイル 2:

一部のヘッダー
A00123465
B99423445
レコード数: 2

したがって、3 番目のファイルにはすべての "A" レコードが最初に来て、次に "B" レコードが続き、合計レコード数が続くようにする必要があります。

出力ファイル:

一部のヘッダー
A12345334
A00123445
A44566555
A00123465
B99423445
B55677
B55683
B66489
レコード数: 8

「A」と「B」内のレコードの並べ替えは関係ありません。

4

9 に答える 9

3

ソース ファイルはソートされているように見えるため、非常に少ないメモリ使用量で処理できます。

入力ファイルと書き込み用の新しいファイルの両方を開くだけです。次に、各入力ファイルから次に利用可能な行を比較し、最初に来る行を出力ファイルに書き込みます。出力ファイルに行を書き込むたびに、元の入力ファイルから次の行を取得します。

両方の入力ファイルが完了するまで続行します。

于 2012-12-17T16:17:18.173 に答える
0

入力ファイルがすでに注文されていると仮定します。

  1. 入力ファイル1と2を開き、出力ファイルを作成します。
  2. ファイル1から最初のレコードを読み取ります。Aで始まる場合は、出力ファイルに書き込みます。Bで始まるレコードに到達するまで、入力ファイル1から読み取りを続けます。
  3. ファイル2から最初のレコードを読み取ります。Aで始まる場合は、出力ファイルに書き込みます。Bで始まるレコードに到達するまで、入力ファイル2から読み取りを続けます。
  4. ファイル1に戻り、「B」レコードを出力ファイルに書き込みます。ストリームの最後に到達するまで、入力ファイル1から読み取りを続けます。
  5. ファイル2に戻り、「B」レコードを出力ファイルに書き込みます。ストリームの最後に到達するまで、入力ファイル2から読み取りを続けます。

この方法により、一度に2行を超えるデータをメモリに保持する必要がなくなります。

于 2012-12-17T16:26:07.623 に答える
0

これは、2 つのファイルをマージ ソートするための、より一般的なボイラー プレート ソリューションのソース コードです。

public static void Merge(string inFile1, string inFile2, string outFile) 
{
    string line1 = null;
    string line2 = null;
    using (StreamReader sr1 = new StreamReader(inFile1))
    {
        using (StreamReader sr2 = new StreamReader(inFile2))
        {
            using (StreamWriter sw = new StreamWriter(outFile))
            {
                line1 = sr1.ReadLine();
                line2 = sr2.ReadLine();
                while(line1 != null && line2 != null)
                {
                    // your comparison function here
                    // ex: (line1[0] < line2[0])
                    if(line1 < line2)
                    {
                        sw.WriteLine(line1);
                        line1 = sr1.ReadLine();
                    }
                    else 
                    {
                        sw.WriteLine(line2);
                        line2 = sr2.ReadLine();
                    }
                }
                while(line1 != null)
                {
                    sw.WriteLine(line1);
                    line1 = sr1.ReadLine();
                }
                while(line2 != null)
                {
                    sw.WriteLine(line2);
                    line2 = sr2.ReadLine();
                }
            }
        }
    }
}
于 2012-12-17T17:31:20.633 に答える
0

レコードが元のファイルで既にソートされていると仮定すると、簡単なアイデアです。

  1. ファイル 2 のループを開始し、すべての A レコードを収集します。
  2. 最初の B レコードに到達したら、それらを別のコレクションに集め始めます。
  3. ファイル 1 をすべて読み取ります。
  4. ファイル 2 から A レコード コレクションの内容を書き出し、次にファイル 1 から読み取った内容を追加し、続いてファイル 2 から B レコードを追加します。

可視化:

<A-data from file 2>
<A-data, followed by B-data from file 1>
<B-data from file 2>
于 2012-12-17T16:20:43.093 に答える
0

メモリが心配な場合、これは挿入ソートの最適なケースであり、各ファイルから一度に 1 行ずつ読み取ります。それが問題にならない場合は、すべてをリストに読み込み、並べ替えを呼び出して書き出します。

並べ替えられたリスト全体をメモリに保持することさえできない場合は、データベースまたはメモリ マップ ファイルを使用することをお勧めします。

于 2012-12-17T16:21:28.080 に答える
0

2 つの並べ替えられたシーケンスがあるため、2 つのシーケンスを 1 つのシーケンスにマージするだけで済みます。これは、MergeSort アルゴリズムの後半が機能するのとほとんど同じです。

残念ながら、IEnumerable提供するインターフェースを考えると、少しごちゃごちゃしてコピーペーストのようになりますが、非常にうまく機能し、非常に小さなメモリフットプリントを使用するはずです:

public class Wrapper<T>
{
    public T Value { get; set; }
}
public static IEnumerable<T> Merge<T>(IEnumerable<T> first, IEnumerable<T> second, IComparer<T> comparer = null)
{
    comparer = comparer ?? Comparer<T>.Default;

    using (var secondIterator = second.GetEnumerator())
    {
        Wrapper<T> secondItem = null; //when the wrapper is null there are no more items in the second sequence

        if (secondIterator.MoveNext())
            secondItem = new Wrapper<T>() { Value = secondIterator.Current };
        foreach (var firstItem in first)
        {
            if (secondItem != null)
            {
                while (comparer.Compare(firstItem, secondItem.Value) > 0)
                {
                    yield return secondItem.Value;
                    if (secondIterator.MoveNext())
                        secondItem.Value = secondIterator.Current;
                    else
                        secondItem = null;
                }
            }
            yield return firstItem;

            yield return secondItem.Value;
            while (secondIterator.MoveNext())
                yield return secondIterator.Current;
        }
    }
}

関数ができたら、Mergeそれはかなり簡単です。

File.WriteAllLines("output.txt",
    Merge(File.ReadLines("File1.txt"), File.ReadLines("File2.txt")))

ファイルReadLinesWriteAllLinesここでは、それぞれが利用IEnumerableされ、それに応じてラインがストリーミングされます。

于 2012-12-17T16:46:24.327 に答える
0

メモリが問題になる場合、おそらくこれを行う最も簡単な方法は、両方のファイルからレコードを読み取り、それらを SQLite または SQL Server Compact データベースに格納し、並べ替えられたレコード セットを返す SELECT クエリを実行することです。並べ替えたいフィールドにインデックスがあることを確認してください。

そうすれば、レコードをメモリに格納する必要がなく、ソート アルゴリズムも必要ありません。データベースはレコードをディスクに保存し、ソートを行います。

于 2012-12-17T16:16:31.547 に答える
0

このアプリケーションにはStreamReaderandを使用することをお勧めします。StreamWriterしたがって、 を使用してファイルを開き、ファイル #1StreamWriterを使用してすべての行をコピーしStreamReader、次にファイル #2 をコピーできます。この操作は非常に高速で、バッファが統合されており、非常に軽量です。

入力ファイルがすでに A と B でソートされている場合は、ソース リーダーを切り替えて、出力をソートすることができます。

于 2012-12-17T16:18:41.967 に答える