【问题标题】:Remove Subdirectories from a QStringList and only keep their parents directories从 QStringList 中删除子目录并仅保留其父目录
【发布时间】:2017-07-24 15:22:10
【问题描述】:

我已经有一个目录路径列表。例如:

/home/aar/las
/home/aar/las/pes
/home/aar/las/fmp
/home/aar/.thumbnails
/home/aar/.thumbnails/normal
/home/aar/yfolder
/home/aar/.kde
/home/aar/.kde/share
/home/aar/.kde/share/config
/home/aar/.kde/share/apps
/home/aar/.kde/share/apps/okular

我想删除所有子目录并只保留父目录。

为此,我使用了运行良好的代码:

QStringList RemoveSubFolders_KeepParentFolders(QStringList FoldersList)
{
    QStringList FoldersList_First = FoldersList;
    QStringList FoldersList_Second = FoldersList;

    QStringList ToDelete;
    foreach (QString TheFolder_First, FoldersList_First) {
        foreach (QString TheFolder_Second, FoldersList_Second) {
            if (TheFolder_Second.startsWith(TheFolder_First) && TheFolder_First.toLower() != TheFolder_Second.toLower())
                ToDelete.append(TheFolder_Second);
        }
    }

    QStringListIterator i(ToDelete);
     while(i.hasNext()){
       FoldersList.removeAll(i.next());
     }

     return FoldersList;  //return list without subfolders
}

结果是:

/home/aar/las
/home/aar/.thumbnails
/home/aar/yfolder
/home/aar/.kde

================================================ =========

问题:

尽管如此,我认为对于大型列表来说,这并不是最好和最快的方式。

有没有最好的方法来完成这项工作?

注意:

  • 我不关心 Windows 或 Ubunutu。
  • 我使用 Qt 5.8 c++。

谢谢。

【问题讨论】:

  • (1) 子目录是否总是紧跟在列表中的目录之后,就像您的示例一样?换句话说,/a ; /b ; /a/x 可能吗? (2) 最终列表中的顺序是否重要?换句话说,如果您以/b ; /b/x ; /a 开头,是否可以以/a ; /b 结尾而不是/b ; /a
  • @IgorTandetnik (1) 我不确定 (2) 订单将是一件好事,但没有必要。
  • 您可以复制路径中/ 最少的文件夹。

标签: c++ list qt for-loop qstring


【解决方案1】:

类似的东西(使用std::vectorstd::string 代替QStringListQString;适应Qt 类留给读者练习):

std::vector<std::string> v;  // populated with directory paths
std::sort(v.begin(), v.end());

std::string root;
auto erase_from = std::unique(v.begin(), v.end(),
  [&root](const std::string& a, const std::string& b) {
    if (root.empty() || a.size() < root.size() || a.compare(0, root.size(), root) != 0) {
      root = a;
    }
    return (b.size() >= root.size() && b.compare(0, root.size(), root) == 0);
  }
);
v.erase(erase_from, v.end());

Demo


再想一想,使用std::remove_if 会更简单、更高效:

std::vector<std::string> v;  // populated with directory paths
std::sort(v.begin(), v.end());

std::string root;
auto erase_from = std::remove_if(v.begin(), v.end(),
  [&root](const std::string& dir) {
    if (root.empty() || dir.size() < root.size() ||
        dir.compare(0, root.size(), root) != 0) {
      root = dir;
      return false;
    }
    return true;
  }
);
v.erase(erase_from, v.end())

Demo

【讨论】:

  • 转念一想,std::remove_if 会更有效率,但我现在没有时间展示示例。可能在一两个小时内,如果你还没有弄清楚的话。
  • 效果很好。对于 i5 中的 13000 条路径,我之前的代码需要将近 16 秒,而你的需要 16 毫秒。慢慢来兄弟。谢谢
  • 已更新为基于std::remove_if 的方法。
【解决方案2】:

这是一个小技巧:保留包含最少 / 的路径

int pathDepth(const QString& path)
{
    return std::count_if(path.begin(), path.end(), [](QChar c) { return c == '/'; });
}

QStringList getParentFolders(const QStringList& folderList)
{
    QStringList ret;
    int minDepth = pathDepth(*std::min_element(folderList.begin(), folderList.end(),
        [](const QString& a, const QString& b){ return pathDepth(a) < pathDepth(b); }));
    foreach (QString path, folderList)
        if (pathDepth(path) == minDepth)
            ret << path;
    return ret;
}

【讨论】:

  • 谢谢。我正在尝试你的代码。稍后我会告诉你结果。
  • 我有这个错误:( 'this' 没有被捕获到这个 lambda 函数 [](const QString& a, const QString& b){ return pathDepth(a)
  • 现在一切正常。我通过将 [] 替换为 [&] 来修复错误。
  • 非常感谢。
  • 我猜你将pathDepth()定义为类成员方法?它应该是一个独立的函数或静态方法:static int pathDepth(...)
猜你喜欢
  • 2017-10-09
  • 2019-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
  • 2020-05-11
相关资源
最近更新 更多