【问题标题】:Convert multi-line if statment to single line with map使用 map 将多行 if 语句转换为单行
【发布时间】:2020-06-10 08:23:07
【问题描述】:

注意:c++98

我对 C++ 有点陌生,我想清理我的代码。我有一个 if 语句检查数组中的数据类型,如果匹配则执行相应的语句。

我想将此多行 if 语句转换为单行,以检查映射中是否存在任何这些类型,以及它们是否执行它。

我的代码:

if (boost::iequals(sqlBufferTypes[i][j], "INTEGER")                 ||
                boost::iequals(sqlBufferTypes[i][j], "INT")         ||
                boost::iequals(sqlBufferTypes[i][j], "BIGINT")      ||
                boost::iequals(sqlBufferTypes[i][j], "uint8_t")     ||
                boost::iequals(sqlBufferTypes[i][j], "uint16_t")    ||
                boost::iequals(sqlBufferTypes[i][j], "LONG"))
            {
                // do stuff
            }

并希望将其转换为类似于:

map<int, string> dataTypes;

dataTypes[1,"INT"];
dataTypes[2,"BIGINT"];
dataTypes[3,"uint8_t"];
dataTypes[4,"uint16_t"];
dataTypes[5,"LONG"];

if (boost::iequals(dataTypes.begin(), dataTypes.end())
{
    // do stuff
}

【问题讨论】:

标签: c++ dictionary boost maps c++98


【解决方案1】:

我想真正的挑战是有一个map&lt;&gt; 不区分大小写地比较键。

您可以通过使用比较谓词来做到这一点:

struct ci_less {
    bool operator()(std::string_view a, std::string_view b) const {
        return boost::lexicographical_compare(a, b, boost::is_iless{});
    }
};

您声明地图使用该谓词:

std::map<std::string, int, ci_less> const dataTypes {
    { "INT",      1 },
    { "BIGINT",   2 },
    { "uint8_t",  3 },
    { "uint16_t", 4 },
    { "LONG",     5 },
};

请注意,它现在是 const,我翻转了键/值对。见下文

一些测试:Live On Coliru

// your sqlBufferTypes[i][j] e.g.:
for (std::string const key : { "uint32_t", "long", "lONg" }) {
    if (auto match = dataTypes.find(key); match != dataTypes.end()) {
        std::cout << std::quoted(key) << " maps to " << match->second;

        // more readable repeats lookup:
        std::cout << " or the same: " << dataTypes.at(key) << "\n"; // throws unless found
    } else {
        std::cout << std::quoted(key) << " not found\n";
    }
}

打印

"uint32_t" not found
"long" maps to 5 or the same: 5
"lONg" maps to 5 or the same: 5

翻转键/值

字典有一个用于在所有语言/库中查找的关键字段。因此,要反向查找,您最终会进行线性搜索(只需查看每个元素)。

在 Boost 中,您可以通过定义多索引容器来获得蛋糕并吃掉它。

多索引

这有助于通过多个索引(包括复合键)进行查找。 (搜索我的答案以获取更多真实示例)

Live On Coliru

#include <boost/algorithm/string.hpp> // for is_iless et al.
#include <string_view>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream> // for std::cout
#include <iomanip> // for std::quoted
#include <boost/locale.hpp>

namespace bmi = boost::multi_index;

struct ci_less {
    bool operator()(std::string_view a, std::string_view b) const {
        return boost::lexicographical_compare(a, b, boost::is_iless{});
    }
};

struct DbType {
    std::string_view name;
    int type_id;

    friend std::ostream& operator<<(std::ostream& os, DbType const& t) {
        return os << "DbType{" << std::quoted(t.name) << ", " << t.type_id << "}";
    }
};

using Map = bmi::multi_index_container<
    DbType,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::tag<struct by_id>,
            bmi::member<DbType, int, &DbType::type_id> >,
        bmi::ordered_unique<
            bmi::tag<struct by_name>,
            bmi::member<DbType, std::string_view, &DbType::name>, ci_less>
    >
>;

int main() {

    Map dataTypes {
        { "INT",      1 },
        { "BIGINT",   2 },
        { "uint8_t",  3 },
        { "uint16_t", 4 },
        { "LONG",     5 },
    };

    auto& idx = dataTypes.get<by_name>();

    // your sqlBufferTypes[i][j] e.g.:
    for (std::string_view const key : { "uint32_t", "long", "lONg" }) {
        if (auto match = idx.find(key); match != idx.end()) {
            std::cout << std::quoted(key) << " -> " << *match << std::endl;
        } else {
            std::cout << std::quoted(key) << " not found\n";
        }
    }
}

打印

"uint32_t" not found
"long" -> DbType{"LONG", 5}
"lONg" -> DbType{"LONG", 5}

Bimap

Boost Bimap 是地图的专门化。它的选项更少,特别是添加了operator[]风格的界面。

using Map = boost::bimap<
    int,
    boost::bimaps::set_of<std::string_view, ci_less>>;

遗憾的是构造函数不支持初始化列表,但是我们可以使用迭代器接口,然后我们使用bimap的right视图进行名称查找:

Live On Coliru

static const Map::relation s_mappings[] = {
    { 1, "INT" },
    { 2, "BIGINT" },
    { 3, "uint8_t" },
    { 4, "uint16_t" },
    { 5, "LONG" },
};

Map const dataTypes { std::begin(s_mappings), std::end(s_mappings) };

// your sqlBufferTypes[i][j] e.g.:
auto& vw = dataTypes.right;
for (std::string_view const key : { "uint32_t", "long", "lONg" }) {
    if (auto match = vw.find(key); match != vw.end()) {
        std::cout << std::quoted(key) << " -> " << match->second << "\n";
    } else {
        std::cout << std::quoted(key) << " not found\n";
    }
}

打印

"uint32_t" not found
"long" -> 5
"lONg" -> 5

【讨论】:

    【解决方案2】:

    根据您的描述,我认为您在示例中切换了键和 id。

    但是,您可以通过为地图引入自定义比较来相当轻松地做您想做的事情。一个简单的方法是先创建一个 lambda 函数:

    auto compare = [](const std::string& a, const std::string& b) {return boost::iequals(a, b); };
    
    std::map < std::string, int, decltype(compare)> mymap = { {"INT", 1},{"BIGINT", 2 }};//and so on
    

    那么你可以这样做:

    if (mymap.count(sqlBufferTypes[i][j])) {//in c++20 can use "contains" instead of "count"
      //do stuff
    }
    

    如果您只想检查并且以后不需要 ID,那么您应该使用 std::set 而不是 map。


    c++98 注意

    中,您不能使用 lambda,但是您仍然可以使用常规结构进行比较谓词:

    struct compare : public std::binary_function<string, string, bool>
    {
        bool operator()(const string& a, const string& b) const
        {
            return boost::iequals(a,b);
        }
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 2014-12-26
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 2021-08-18
      • 2023-04-08
      • 2014-10-08
      相关资源
      最近更新 更多