将n组文件组合在一起(随机且无重复)

时间:2015-01-06 15:38:25

标签: c++ algorithm sorting merge

我有以下几组文件:

每个文件都被描述为以下type-ID-pageNumber-R.xml,即jugement_017_3

设置1:

 - Conclusions-009-1-R.xml   
 - Conclusions-010-1-R.xml 
 - Conclusions-011-1-R.xml

设置2:

 - Assignation-043-1-R.xml    
 - Assignation-043-2-R.xml 
 - Assignation-045-1-R.xml 

设置3:

 - Jugement-017-1-R.xml     
 - Jugement-017-2-R.xml  
 - Jugement-017-3-R.xml 
 - Jugement-018-1-R.xml 
 - Jugement-018-2-R.xml 

我希望使用以下规则将set 1set 2set 3合并到set 4中:

  1. 随机组合顺序(每次我们想要组合文件时,第4组中的顺序都会改变)
  2. 相同类型的文件可以一个接一个地放置如果它们具有相同的 ID

  3. 设置4:

    - Conclusions-009-1-R.xml 
    - Jugement-018-1-R.xml 
    - Jugement-018-2-R.xml 
    - Assignation-043-1-R.xml    
    - Assignation-043-2-R.xml
    - Conclusions-010-1-R.xml 
    - Assignation-045-1-R.xml 
    - Conclusions-011-1-R.xml
    - Jugement-017-1-R.xml     
    - Jugement-017-2-R.xml  
    - Jugement-017-3-R.xml
    

2 个答案:

答案 0 :(得分:2)

这是我的0.05美元实施,详细说明我的评论:

  1. 将所有章节存储在由唯一(部分,章节编号)键入的集合中:

    using Section = std::string;
    using Page    = int;
    using Chapter = int;
    using Pages   = icl::interval_set<Page>::type;
    
    struct Module {
        Section section;
        Chapter chapter;
    
        bool operator<(Module const& o) const;
    };
    
    using Table = std::map<Module, Pages>;
    

    如您所见,我选择了一个用于存储页面范围的间隔集。无论输入顺序如何,这都可以更容易地进行合并。

  2. 让我们这样做。我按“随机”顺序填写表格:

     struct Fill { Section s; Chapter c; Page p; };
     for (auto& fill : std::vector<Fill> { 
         { "Jugement",    18 , 2 },
         { "Conclusions", 11 , 1 },
         { "Assignation", 43 , 1 },
         { "Assignation", 43 , 2 },
         { "Conclusions", 10 , 1 },
         { "Jugement",    17 , 3 },
         { "Assignation", 45 , 1 },
         { "Jugement",    17 , 1 },
         { "Conclusions", 9  , 1 },
         { "Jugement",    17 , 2 },
         { "Jugement",    18 , 1 },
     })
     {
         table[{fill.s, fill.c}] += fill.p; // add page to (existing) range
     }
    

    这就是全部!

  3. 现在我们可以按照章节/章节打印模块:

     std::cout << "------------- table: \n";
     for (auto& r:table)
         std::cout << r << "\n";
    

    打印:

     ------------- table: 
     Assignation    43  {[1,2]}
     Assignation    45  {[1,1]}
     Conclusions    9   {[1,1]}
     Conclusions    10  {[1,1]}
     Conclusions    11  {[1,1]}
     Jugement   17  {[1,3]}
     Jugement   18  {[1,2]}
    
  4. 现在我们创建了所需的订单,让我们添加一些不可预测性(与混乱略有不同)。

    using rv = rw<Table::value_type>;
    std::vector<rv> vw(begin(table), end(table));
    
    // blind shuffle
    srand(time(0));
    std::random_shuffle(vw.begin(), vw.end());
    

    的Bam。我们有一个对模块表条目的引用的混乱视图。 但是!随机不是目标。

    因此,我们从匹配的部分中找到相邻的对,并尝试通过旋转它们来移除它们。当然,可能没有任何东西可以交换(来自另一部分),在这种情况下,我们将副本留在尾随位置:

    // try to avoid subsequent modules from equal sections (dup)
    auto dup     = [](rv a, rv b) { return a.get().first.section == b.get().first.section; };
    auto it      = vw.begin();
    auto const e = vw.end();
    
    while(it != e) { // bit redundant, could be while(true)
        it = std::adjacent_find(it, e, dup);
        if (it == e) 
            break;
    
        auto m = std::find_if(it+1, e, [&] (rv r) { return r.get().first.section != it->get().first.section; });
    
        if (m == e) {
            it = m;
        } else {
            std::rotate(it+1, m, e);
            it = std::adjacent_find(it, e, dup);
        }
    }
    
  5. 当然,打印出结果选择:

    std::cout << "------------- selection: \n";
    for (auto& r : vw)
        std::cout << r.get() << "\n";
    
  6. 可以在此处看到打印一些诊断/跟踪信息的版本:

    <强> Live On Coliru

    enter image description here

    完整列表

    <强> Live On Coliru

    #include <boost/bind.hpp>
    #include <boost/icl/interval_set.hpp>
    #include <boost/tuple/tuple_comparison.hpp>
    #include <iomanip>
    #include <iostream>
    #include <map>
    
    namespace icl = boost::icl;
    
    template<typename T> using rw = boost::reference_wrapper<T>;
    
    using Section = std::string;
    using Page    = int;
    using Chapter = int;
    using Pages   = icl::interval_set<Page>::type;
    
    struct Module {
        Section section;
        Chapter chapter;
    
        bool operator<(Module const& o) const { return boost::tie(section,chapter) < boost::tie(o.section,o.chapter); }
    };
    
    using Table = std::map<Module, Pages>;
    
    static inline std::ostream& operator<<(std::ostream& os, Table::value_type const& p) {
        return os << p.first.section << "\t" << p.first.chapter << "\t" << p.second;
    }
    
    int main()
    {
        std::cout << std::unitbuf;
        Table table;
    
        {
            struct Fill { Section s; Chapter c; Page p; };
            for (auto& tup : std::vector<Fill> { 
                { "Jugement",    18 , 2 },
                { "Conclusions", 11 , 1 },
                { "Assignation", 43 , 1 },
                { "Assignation", 43 , 2 },
                { "Conclusions", 10 , 1 },
                { "Jugement",    17 , 3 },
                { "Assignation", 45 , 1 },
                { "Jugement",    17 , 1 },
                { "Conclusions", 9  , 1 },
                { "Jugement",    17 , 2 },
                { "Jugement",    18 , 1 },
            })
            {
                table[{tup.s, tup.c}] += tup.p; // add page to (existing) range
            }
        }
    
        std::cout << "------------- table: \n";
        for (auto& r:table)
            std::cout << r << "\n";
    
        {
            using rv = rw<Table::value_type>;
            std::vector<rv> vw(begin(table), end(table));
    
            // blind shuffle
            srand(time(0));
            std::random_shuffle(vw.begin(), vw.end());
    
            // try to avoid subsequent modules from equal sections (dup)
            auto dup     = [](rv a, rv b) { return a.get().first.section == b.get().first.section; };
            auto it      = vw.begin();
            auto const e = vw.end();
    
            while(it != e) // bit redundant, could be while(true)
            {
                std::cout << "------------- STATE: \n";
                for (auto& rv:vw)
                    std::cout << rv.get() << (it->get_pointer() == rv.get_pointer()? "*\n":"\n");
    
                it = std::adjacent_find(it, e, dup);
                if (it == e) 
                    break;
    
                std::cout << "------------- dupes: \n";
                std::cout << "\t" << (it+0)->get() << "\n";
                std::cout << "\t" << (it+1)->get() << "\n";
    
                auto m = std::find_if(it+1, e, [&] (rv r) { return r.get().first.section != it->get().first.section; });
    
                if (m == e)
                {
                    it = m;
                } else
                {
                    std::cout << "------------- rotating to: \n";
                    std::cout << "\t" << m->get() << "\n";
    
                    std::rotate(it+1, m, e);
    
                    it = std::adjacent_find(it, e, dup);
                }
            }
            std::cout << "------------- selection: \n";
            for (auto& r : vw)
                std::cout << r.get() << "\n";
        }
    }
    

答案 1 :(得分:1)

如果你能以某种方式消除连续放置具有相同ID的文件的第二个要求,你的问题可以减少到well-known algorithm for random shuffling

您可以通过混洗文件组而不是单个文件来解决此问题(当然,一个组可能只包含一个文件)。

  • 创建一个表示具有特定类型和ID以及一组页面的文件组的数据结构
  • 将您的文件列表组合成
  • 对群组
  • 运行随机随机播放
  • 将结果展开回单个文件列表

以下是此组结构的外观:

class FileGroup {
    string name;
    string id;
    set<int> pages;
public:
    FileGroup(const string& _name, const string& _id) : name(_name), id(_id) {}
    void addPage(int pg) { pages.insert(pg); }
    ...
};

您的样本数据如下所示:

"Assignation" - "043" - { 1, 2 }
"Assignation" - "045" - { 1 }
"Conclusions" - "009" - { 1 }
"Conclusions" - "010" - { 1 }
"Conclusions" - "011" - { 1 }
"Judgement"   - "017" - { 1, 2, 3 }
"Judgement"   - "018" - { 1, 2 }

现在相关文件的页面将保持在一起,无论你以什么方式改组。