有条件的打印和计数在 std::map 上有限制

Conditional printing and counting over std::map with restrictions

本文关键字:std map 有限制 打印 有条件      更新时间:2023-10-16

我目前正在学习 C++17,作为练习使用标准库的一部分,我们遇到了一个挑战,以习惯使用这些功能:

  1. 循环访问std::map<std::string, size_t>(也称为std::map<file_name, file_size>(
  2. 打印空size_t == 0文件名并返回其计数
  3. 打印非空size_t != 0文件名并返回其计数
  4. 从地图std::pairswhose size_t == 0中删除

限制:

  1. 只能使用标头:<vector><map><string><algorithm><functional>

  2. 无法定义复杂类型或模板

  3. 无法使用. (member access), -> (member access via pointer), * (dereference) operators

  4. 不能使用for, while, do-while nor if-else, switch和其他条件

  5. 可以使用函数模板的std::for_each和其他函数来迭代元素集合

  6. 无λ

  7. 没有std::coutstd::cerrstd::ostream等。

  8. 无自动类型

  9. 可以使用其他函数,只要它们包含在限制 #1 中描述的标头中

允许使用以下函数:

void print(const std::string& str)
{
std::cout << str << std::endl;
}
std::string split(const std::pair<std::string, size_t> &r)
{
std::string name;
std::tie(name, std::ignore) = r;
return name;
}
bool checkEmpty(const std::pair<std::string, size_t>& r, bool trueIfIsNot
)
{
file_size size;
std::tie(std::ignore, size) = r;
bool result = (size == 0);
if (trueIfIsNot)
{
result = !result;
}
return result;
}

在我之前的帖子中,我开始欣赏std::bindstd::for_each的使用。这一次,如何在不使用限制 #4 所述的语法的情况下添加谓词和条件来修改输出?

我目前正在考虑使用std::transform()std::copy_if()等。我对标准库的许多功能都有一些了解,但我认为我在语法上非常薄弱,无法理解事物如何协同工作,因此我不知道如何使用它们。

对于 2,3 个任务,您可以执行:

  • 使用初始大小的vector作为地图大小
  • 使用copy_if根据条件从地图复制元素
  • for_each与有界split/print
  • 一起使用
  • 返回 Vector 中第一个项和最后一个项之间的差项数

代码:

int task2and3(const std::map<std::string,int>& m, bool trueIfIsNot)
{
std::vector<std::pair<std::string,int>> vec(m.size());
auto firstPastEnd = std::copy_if(m.begin(),m.end(),vec.begin(),
std::bind(checkEmpty,std::placeholders::_1,trueIfIsNot));
std::for_each(vec.begin(), firstPastEnd, 
std::bind(print,std::bind(split,std::placeholders::_1)));
return firstPastEnd - vec.begin();
}

通过trueIfIsNot您可以指示打印哪些对(值为 0 或其他值(。


要执行第 4 个任务,您还可以使用vector来存储map的项目。要从映射中删除元素,您可以在 vector 中迭代这些项目(使用for_each(并调用map::erase方法。由于此函数成员具有重载,因此需要正确强制转换它以指示通过key_type删除元素的方法。使用split从配对中获取此key_type

void task4(std::map<std::string,int>& m)
{
std::vector<std::pair<std::string,int>> vec(m.size());
auto firstPastEnd = std::copy_if(m.begin(),m.end(),vec.begin(),std::bind(checkEmpty,std::placeholders::_1,false));
using sizeType = std::map<std::string,int>::size_type;
using keyType = std::map<std::string,int>::key_type;
for_each(vec.begin(), firstPastEnd, 
std::bind( static_cast<sizeType (std::map<std::string,int>::*)(const keyType&) >(&std::map<std::string,int>::erase),
&m,
std::bind(split,std::placeholders::_1)) );
}

完整演示