【问题标题】:Sort relative paths排序相对路径
【发布时间】:2017-04-17 00:20:56
【问题描述】:

我的问题很简单,但我想不出一个优雅的解决方案。
在我的应用程序中,从用户输入中收集了一堆相对路径(它们实际上并不存在于文件系统中)。
举个例子:

  • somefile.ext
  • z/file.ext
  • A/B/file2.ext
  • A/B/z/file.ext
  • file1.ext
  • A/B/file.ext

这些被收集在一个 QList 中(其中包含指向具有作为 QString 成员的路径的类的实例的指针),但容器对我来说并不重要。
期望的结果是使列表以有序的形式出现,目录覆盖文件(正如我们在大多数文件管理器中使用的那样),基本上就像你会创建一个真正的文件系统一样。

  • A/B/z/file.ext
  • A/B/file.ext
  • A/B/file2.ext
  • z/file.ext
  • 文件.ext
  • somefile.ext

显然,基于普通字符串的排序是行不通的,但是对这样的列表进行排序的最优雅/最简单的方法是什么?

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    我会为内置排序编写一个自定义的comparator 函数。这样的事情可能会奏效:

    auto cmp = [](const string& lhs, const string& rhs) {
        int len = min(lhs.size(), rhs.size());
        for (int i = 0; i < len; i++) {
            if (lhs[i] = rhs[i]) continue;
    
            // check if there is a '/' starting from position i in both paths
            // put directory first (if only one is a directory)
            // or return lhs[i] < rhs[i]
    };
    

    完成这段代码应该相当容易, 然后

    sort(begin(paths), end(paths), cmp);
    

    请注意,我使用的是 c++11

    【讨论】:

    • 如果我理解正确,伪代码如下所示:if (a.count('/') != b.count('/') return a.count('/') &gt; b.count('/'); return a &lt; b; 但这会将“X/X/X/file.ext”排序在“A/A/file.ext”之上。跨度>
    • @ldr 如果您不只是将if one has more '/' 更改为if one has any '/' and the others doesn't than... ,我假设您首先需要“更深”的目录(基于目录与文件的要求)
    • 我不知道are_in_dirs 检查应该有什么用处。如果将somefilex/somefile 进行比较,您的循环将在第一个字符处结束,而are_in_dirs 将保持为假,因此您将返回s &lt; x。其余的 cmets 对我来说听起来不错。
    • 你说得对,这个检查是不必要的,我把它去掉了。
    【解决方案2】:

    退后一步,花点时间用简单的英语总结一下您想要的排序标准:

    1. 目录第一,文件第二。

    2. 目录按字母排序,文件按字母排序。

    现在,一旦您的逻辑被简化为这种简单、直接的定义,只需将此逻辑直接转换为 C++ 代码。

    首先,将每个字符串转换为单个值,0 或 1,表示该字符串是否具有路径名组件。

    对此进行排序。然后,如果两个字符串的值相等,则像往常一样对字符串本身进行排序。简单:

    std::sort(container.begin(),
              container.end(),
              []
              (const QString &a,
               const QString &b)
              {
                 // Compute whether a or b is a subdirectory, representing
                 // each as:
                 //
                 // 0: directory
                 // 1: file
    
                 int a_hier=a.contains('/') ? 0:1;
                 int b_hier=b.contains('/') ? 0:1;
    
                 if (a_hier != b_hier)
                      return a_hier < b_hier;
    
                 return a < b;
             });
    

    这是您基本的初始方法。如有必要,可以对此进行调整,以稍微不同的目录对路径名进行排序(因为路径名中的 / 组件参与了相对排序顺序,您可能想要也可能不想要,这在您的问题中不清楚)。

    【讨论】:

    • 这将例如在“A/B/file.ext”之后排序“A/B/z/file.ext”。我希望它基本上像一个目录树。我编辑了问题以反映这一点。
    • 我认为可能是这样。但是,您应该能够接受我的答案,并自己弄清楚。这只是一些额外的步骤,超出了已经概述的内容。只需准确地说明此处的附加比较逻辑应该如何工作,用简单的英语,使用简短、简短、合乎逻辑的句子。然后schedule an appointment with your rubber duck。一旦您的橡皮鸭同意您提出的算法可以工作,只需将其直接翻译成 C++ 代码。任务完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 2010-09-15
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 2010-12-17
    相关资源
    最近更新 更多