提问人:tadpole 提问时间:9/26/2022 最后编辑:JeJotadpole 更新时间:10/29/2022 访问量:127
有没有一种简单的方法可以重构此代码?
Is there a simple way of refactoring this code?
问:
我有一个具有非常相似的重复代码的函数。我喜欢重构它,但不想要任何复杂的映射代码。
该代码基本上过滤掉了表中的列。我通过让比较语句具有简单类型使这个示例变得简单,但实际的比较可能更复杂。
我希望可能有一些模板或 lambda 技术可以做到这一点。
vector<MyRecord*>& MyDb::Find(bool* field1, std::string * field2, int* field3)
{
std::vector<MyRecord*>::iterator iter;
filterList_.clear();
std::copy(list_.begin(), list_.end(), back_inserter(filterList_));
if (field1)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field1 != *field1)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
if (field2)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field2 != *field2)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
if (field3)
{
iter = filterList_.begin();
while (iter != filterList_.end())
{
MyRecord* rec = *iter;
if (rec->field3 != *field3)
{
filterList_.erase(iter);
continue;
}
iter++;
}
}
return filterList_;
}
更新:以防万一有人好奇,这是我的最终代码。再次感谢大家。非常容易理解和维护。
vector<MyRecord*>& MyDb::Find(bool* field1, std::string* field2, int* field3)
{
auto compare = [&](MyRecord* rec) {
bool add = true;
if (field1 && rec->field1 != *field1) {
add = false;
}
if (field2 && rec->field2 != *field2) {
add = false;
}
if (field3 && rec->field3 != *field3) {
add = false;
}
return add;
};
filterList_.clear();
std::copy_if(list_.begin(), list_.end(), back_inserter(filterList_), compare);
return filterList_;
}
答:
1赞
JeJo
9/26/2022
#1
有没有一种简单的方法可以重构此代码?
据我了解您的算法/意图,使用 std::erase_if
(c++20) 您可以替换整个 while 循环,如下所示(演示代码):
#include <vector> // std::erase_if
std::vector<MyRecord*> // return by copy as filterList_ is local to function scope
Find(bool* field1 = nullptr, std::string* field2 = nullptr, int* field3 = nullptr)
{
std::vector<MyRecord*> filterList_{ list_ }; // copy of original
const auto erased = std::erase_if(filterList_, [=](MyRecord* record) {
return record
&& ((field1 && record->field1 != *field1)
|| (field2 && record->field2 != *field2)
|| (field3 && record->field3 != *field3));
}
);
return filterList_;
}
如果不支持 C++20,也可以使用擦除-删除习惯用语,这实际上发生在 .std::erase_if
评论
0赞
tadpole
9/26/2022
感谢 JeJo 和其他人。我认为你的答案是我所寻找的最相关的答案。我会稍微改变一下。我将使用 find_if 并添加到列表中而不是删除。
0赞
JeJo
9/26/2022
@tadpole 我认为另一个答案是你想要的更多,因为你使用副本。
2赞
apple apple
9/26/2022
#2
你可以使用 std::copy_if
(因为你已经/无论如何都会做一个副本)
vector<MyRecord*>& MyDb::Find(bool* field1, std::string* field2, int* field3){
filterList_.clear();
std::copy_if(list_.begin(), list_.end(), back_inserter(filterList_),[&](MyRecord* rec){
// whatever condition you want.
return field3 && rec->field3 != *field3;
});
return filterList_;
}
评论
if ((field1 && rec->field1 != *field1)) || (field2 && rec->field2 != *field2) || (field3 && rec->field3 != *field3) { ...}
.预先删除和其他检查,运行一次循环,一次检查所有三个字段。if (field1)