0

現在、1 つまたは 2 つのキー フィールドに 10.000.000 を超えるレコードを持つ 2 つのパイプ分割ファイルを結合する C++ 関数を作成しようとしています。

フィールドは次のようになります



    P2347|John Doe|C1234
    P7634|Peter Parker|D2344
    P522|Toni Stark|T288



    P2347|Bruce Wayne|C1234
    P1111|Captain America|D534
    P522|Terminator|T288

フィールド 1 と 3 を結合するには、予想される出力が次のように表示されるはずです。



    P2347|C1234|John Doe|Bruce Wayne
    P522|T288|Toni Stark|Terminator

私が現在考えているのは、セット/配列/ベクトルを使用してファイルを読み取り、次のようなものを作成することです:



    P2347|C1234>>John Doe
    P522|T288>>Toni Stark



    P2347|C1234>>Bruce Wayne
    P522|T288>>Terminator

次に、スリップの最初の部分をキーとして使用し、それを 2 番目のセット/ベクトル/配列と照合します。

私が現在持っているものは次のとおりです。最初のファイルを読み取り、2 番目のファイルを行ごとにセットと照合します。行全体を取得して一致させます。



    #include iostream>
    #include fstream>
    #include string>
    #include set>
    #include ctime>
    using namespace std;

    int main()
    {

        clock_t startTime = clock();

        ifstream inf("test.txt");
        set lines;
        string line;
        for (unsigned int i=1; std::getline(inf,line); ++i)
            lines.insert(line);

        ifstream inf2("test2.txt");

        clock_t midTime = clock();

        ofstream outputFile("output.txt");  
        while (getline(inf2, line))
        {
            if (lines.find(line) != lines.end())
                outputFile > a;
        return 0;

}

どんな提案でもとてもうれしいです。また、より良い (より速い) 方法があれば、コンセプト全体を喜んで変更します。1,000 万を超えるレコードが存在する可能性があるため、速度は非常に重要です。

編集:別のアイデアは、マップを取得し、キーをキーにすることです-ただし、これは少し遅くなる可能性があります. 助言がありますか?

助けてくれてありがとう!

4

1 に答える 1

0

このタスクを完了するために複数の方法を試しましたが、これまでのところどれも効率的ではありませんでした。

すべてをセットに読み込み、キー フィールドを次の形式に解析します: キー >> 配列型セットをシミュレートする値。解析には長い時間がかかりましたが、メモリ使用量は比較的低いままです。完全に開発されていないコード:



        #include \
        #include \
        #include \
        #include \
        #include \
        #include \
        #include \
        std::vector &split(const std::string &s, char delim, std::vector &elems) {
        std::stringstream ss(s);
        std::string item;
        while (std::getline(ss, item, delim)) {
            elems.push_back(item);
        }
        return elems;
    }


    std::vector split(const std::string &s, char delim) {
        std::vector elems;
        split(s, delim, elems);
        return elems;
    }

    std::string getSelectedRecords(std::string record, int position){

        std::string values;
        std::vector tokens = split(record, ' ');




        //get position in vector
        for(auto& s: tokens)
            //pick last one or depending on number, not developed
            values = s;

        return values;
    }

    int main()
    {

        clock_t startTime = clock();

        std::ifstream secondaryFile("C:/Users/Batman/Desktop/test/secondary.txt");
        std::set secondarySet;
        std::string record;

        for (unsigned int i=1; std::getline(secondaryFile,record); ++i){
            std::string keys = getSelectedRecords(record, 2);
            std::string values = getSelectedRecords(record, 1);
            secondarySet.insert(keys + ">>>" + values);
        }

        clock_t midTime = clock();

        std::ifstream primaryFile("C:/Users/Batman/Desktop/test/primary.txt");
        std::ofstream outputFile("C:/Users/Batman/Desktop/test/output.txt");

        while (getline(primaryFile, record))
        {
            //rewrite find() function to go through set and find all keys (first part until >> ) and output values
            std::string keys = getSelectedRecords(record, 2);

            if (secondarySet.find(keys) != secondarySet.end())
                outputFile > a;
        return 0;
        }

現在、パイプ分割の代わりにスペース分割を使用していますが、それは問題にはなりません。データの読み取りは非常に高速ですが、解析には非常に時間がかかります

もう 1 つのオプションは、マルチマップを取得することでした。値を指すキー フィールドと同様の概念ですが、これは非常に低く、メモリを集中的に使用します。



    #include \
    #include \
    #include \
    #include \
    #include \
    #include \
    #include \

    int main()
    {


    std::clock_t startTime = clock();

    std::ifstream inf("C:/Users/Batman/Desktop/test/test.txt");
    typedef std::multimap Map;
    Map map;

    std::string line;

    for (unsigned int i=1; std::getline(inf,line); ++i){
        //load tokens into vector
        std::istringstream buffer(line);
        std::istream_iterator beg(buffer), end;
        std::vector tokens(beg, end);
        //get keys
        for(auto& s: tokens)
            //std::cout >>" second;
            outputFile > a;
    return 0;
    }

さらに考えることは次のとおりです。データをインポートするときに、パイプ分割されたファイルをそれぞれ 1 列ずつ別のファイルに分割します。これで、何も解析する必要がなくなり、各列を個別に読み取ることができます。

編集: 再帰分割関数を使用して最初の例を最適化しました。それでも 100.000 レコードで 30 秒以上です。より速く、実際の find() 関数がまだ欠落していることを確認したいと思います。

何かご意見は?ありがとう!

于 2013-10-12T19:35:52.417 に答える