【问题标题】:Avoid if-else nesting using maps使用映射避免 if-else 嵌套
【发布时间】:2016-07-07 08:50:46
【问题描述】:

比如我有这样的嵌套

if (scale < 2 ) {turn = "First";
} else if (scale < 5) {turn = "Second";
} else if (scale < 8) {turn = "Third";
}

e.t.c

如何使用映射来避免它,它应该可以帮助我使用一个 if 条件。

【问题讨论】:

  • 限制总是等距的(即 5-2=3、8-5=3)还是只是巧合?

标签: c++


【解决方案1】:

您甚至可以使用简单的排序数组:

struct TurnRank
{
    int rank;
    const char* turn;
};

bool RankComp(int lhs, const TurnRank& rhs) { return lhs < rhs.rank; }

const TurnRank kTurnRank[] = {
    {2, "First"},
    {5, "Second"},
    {8, "Third"},
};

这不需要动态分配并且可读性很好。

现在进行查找,使用 std::upper_bound:

#include <algorithm>
#include <iostream>
#include <iterator>

void print_turn(int rank)
{
    auto first = std::begin(kTurnRank), last = std::end(kTurnRank);
    auto it = std::upper_bound(first, last, rank, RankComp);

    if (it == last) std::cout << "Error, rank " << rank << " too large!\n";
    else            std::cout << it->turn << "\n";
}

【讨论】:

    【解决方案2】:

    我认为,这样的东西可以提供最好的性能:

    // Predefined constants.
    const char *scaleNames[] = {"First", "First", "Second", "Second",
        "Second", "Third", "Third", "Third"};
    const int namesCount = sizeof(scaleNames) / sizeof(*scaleNames);
    
    <...>
    
    turn = (0 <= scale && scale < namesCount) ? scaleNames[scale] : "Unknown";
    

    如果您确定scale 始终有效,当然可以省略检查。

    【讨论】:

    • 通过数组索引直接映射可能是一个巧妙的技巧(例如,这是这种方法的一个很好的demonstration)。不过,它不能扩展,也不能用于否定键:-)
    • @KerrekSB 它提供了良好的性能:O(1) 而不是 O(N) 与直接迭代或 O(logN) 与二分查找。它很容易阅读。它可以与static_assert 结合使用,这样您就不会忘记扩展名称数组。可以轻松更改否定键的行为。在很多情况下都是一个好方法,不是吗?
    • 是的,在适当的情况下(例如,当您的密钥密集时),这无疑是一种有用的技术。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    相关资源
    最近更新 更多