【问题标题】:Using std::equal_range to find the range of prefixes that occur in a vector of strings使用 std::equal_range 查找出现在字符串向量中的前缀范围
【发布时间】:2018-06-08 13:34:32
【问题描述】:

我正在尝试提出一个 lambda,它允许 std::equal_range 返回一个范围,其中搜索的字符串作为前缀存在。由于这可能措辞不正确,举个例子:

给定字符串向量:

  • C:\users\andy\documents\screenshot.jpg
  • C:\users\bob\desktop\file.txt
  • C:\users\bob\desktop\picture.png
  • C:\users\bob\desktop\video.mp4
  • C:\users\john\desktop\note.txt

我希望返回的迭代器是

  • C:\users\bob\desktop\file.txt 和
  • C:\users\bob\desktop\video.mp4.

我将如何为 std::equal_range 编写一个比较 lambda 来完成此任务,或者 std::equal_range 不是适合这项工作的工具?

【问题讨论】:

  • std::equal_range 的四参数重载与比较可调用对象似乎足以完成任务。只需编写一个实现与前缀匹配的比较的比较对象。您必须仔细使用separate implementations of comp(element, value) and comp(value, element) 对比较对象进行编码,才能返回正确的比较结果。
  • 这似乎可行,但我不确定它是否完全正确:ideone.com/NiV02v 您可以使用std::string.compare 避免使用substr,但这对我来说更清楚了。 耸耸肩
  • 我会采用一种比 Retired Ninja 稍微复杂的方法。我会将前缀字符串强制转换为不是std::string 的独特辅助类型。那我就可以区分这两种比较函数了,在自定义比较器类中实现两个operator()s,比较prefix to string,prefix to string。
  • C:\users\bob\desktop\picture.png为什么不应该被退回呢?
  • 使用<=>= 打破了严格的弱排序要求进行比较。这个答案比我能解释得更好。 :) stackoverflow.com/a/981299/920069

标签: c++ string search range


【解决方案1】:

我认为您只需要让 比较器 仅将前缀的长度与这样的元素进行比较:

std::vector<std::string> v
{
    "C:/users/andy/documents/screenshot.jpg",
    "C:/users/bob/desktop/file.txt",
    "C:/users/bob/desktop/picture.png",
    "C:/users/bob/desktop/video.mp4",
    "C:/users/john/desktop/note.txt",
};

std::sort(std::begin(v), std::end(v));

std::string const prefix = "C:/users/bob/desktop/";

auto lb = std::lower_bound(std::begin(v), std::end(v), prefix);

// For the upper bound we want to view the vector's data as if
// every element was truncated to the size of the prefix.
// Then perform a normal match.
auto ub = std::upper_bound(lb, std::end(v), prefix,
[&](std::string const& s1, std::string const& s2)
{
    // compare UP TO the length of the prefix and no farther
    if(auto cmp = std::strncmp(s1.data(), s2.data(), prefix.size()))
        return cmp < 0;

    // The strings are equal to the length of the prefix so
    // behave as if they are equal. That means s1 < s2 == false
    return false;
});

// make the answer look like we used std::equal_range
// (if that's what's needed)
auto range = std::make_pair(lb, ub);

for(auto itr = range.first; itr != range.second; ++itr)
    std::cout << *itr << '\n';

输出:

C:/users/bob/desktop/file.txt
C:/users/bob/desktop/picture.png
C:/users/bob/desktop/video.mp4

为了解释为什么这样可行,想象一下获取向量并对其进行排序。然后想象访问每个元素并将它们截断为前缀的长度。您将得到一个排序后的向量,其元素长度不超过前缀。那时,一个简单的std::equal_range 就可以满足您的要求。因此,我们需要做的就是构建一个比较器,其行为就好像容器元素已被截断为前缀的长度,并在我们的std::equal_range 中使用该比较器搜索(或双胞胎std::lower_bound/upper_bound 搜索)。

【讨论】:

  • 根据我对上述 Sam Varshavchik 的 cmets 的理解,您必须同时使用 comp(element, value) 和 comp(value, element) 进行比较,对吗?另外,在这里使用 string::compare 会更快吗?
  • @AndrewLeFevre 是的,你是对的。这比我想象的要棘手。我会考虑更多。
  • @AndrewLeFevre 我相信这个问题现在已经解决了。
猜你喜欢
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 2019-11-26
相关资源
最近更新 更多