【问题标题】:What is the best way to make a nested list in C++?在 C++ 中创建嵌套列表的最佳方法是什么?
【发布时间】:2021-07-21 05:03:23
【问题描述】:

对于懂 Python 的人来说,最好的方式来解释我想要的是类比:

[1, [2, 3], 4, [5, [6]], 7]

显然,我可以实现 my own class (template) 来做到这一点,但如果标准库已经发明了这个轮子,我想避免 重新 - 发明它(或至少,避免将我半生不熟的重新发明版本放在我的项目中)。

【问题讨论】:

  • “最佳方式”似乎我们应该根据意见关闭。你只想要std::list<std::any>吗?
  • 您有什么要求?你对“最好”的定义是什么?看来你已经有了实现,有什么问题?
  • 来一个实际的例子来说明你为什么想要这个怎么样?上面的建议基本上是为您提供您所要求的,但这不是 C++ 中通常使用 的那种东西。 Pythonic 技术和数据结构往往不能很好地转换为 C++。
  • 这是treeint 吗?
  • 请根据您的要求提供一个真实世界的场景。详细说明您的要求。

标签: c++ data-structures


【解决方案1】:

在底层,python 列表是一个动态重新分配的数组,即与std::vector 相同的东西,它的元素是动态的,即与std::any 相同的东西。所以这段代码最直接的类似物是

using p = std::vector<std::any>;

auto myList = p { 1, p { 2, 3 }, 4, p { 5, p { 6 } }, 7};

【讨论】:

  • 不错!我什么都不知道。但是,如果我希望所有“叶子”元素都属于同一类型(例如 int)怎么办?
  • @allyourcode 你说的是树吗?
  • @allyourcode:那么你所做的实际上与你引用的 python 示例非常不同,因为 python 也可以让你编写类似 [1.0, [ 2, 3], "四", [lambda x: 5, [6]], 7].
  • @allyourcode:也就是说,这是一个完全不同的问题
  • @allyourcode 的主要问题是:您是否关心在数组中嵌套数组的可能性,还是能够存储每种可能的类型(或两者兼而有之?)。因为有很多选项取决于您的确切要求:例如已经提到std::anystd::variant 也可以在这里工作。但在我看来,您正在寻找像树/图这样的自定义数据结构。如果是这样,您可以尝试boost。或者,根据您的具体要求,也许只需要std::(multi)set 就可以了。
【解决方案2】:

因此,您的值的类型将包含 int 或相同类型的值向量。

这可以通过std::variant 来实现,该结构允许类型的递归性质(以及一个允许使用所需语法对其进行初始化的构造函数)

template<typename T>
struct nested_list : std::variant<std::vector<nested_list<T>>, T> {
    using std::variant<std::vector<nested_list<T>>, T>::variant;

    nested_list(std::initializer_list<nested_list> ilist)
        : std::variant<std::vector<nested_list<T>>, T>(
              std::in_place_index<0>, ilist) {}

    // You can also add some helper methods like "get_vector", "is_vector", etc.
};

使用示例:

template<typename T>
std::ostream& operator<<(std::ostream& os, const nested_list<T>& lst) {
    if (auto* v = std::get_if<0>(&lst)) {
        os << '{';
        bool first = true;
        for (const auto& child : *v) {
            if (first) first = false;
            else os << ", ";
            os << child;
        }
        os << '}';
    } else if (auto* e = std::get_if<1>(&lst)) {
        os << *e;
    } else {
        os << "<valueless by exception>";
    }
    return os;
}

int main() {
    nested_list<int> x = {1, {2, 3}, 4, {5, {6}}, 7};
    std::cout << x << '\n';
}

【讨论】:

  • 哇!我很惊讶您可以让nested_list 继承自nested_list 派生的东西!对我来说,这是解决方案的主要关键。
  • 我一直在尝试学习变体。我理解基本概念,但像 in_place_index 这样的东西让我感到困惑。我猜你说的是使用第一个(即两个中的索引 0)可能的类型,即 vector<...> ?我想这是需要的,否则它可能(或肯定是?)在初始化期间应该选择哪种类型变体不明确?
  • @allyourcode 你对构造函数的作用是完全正确的。有关更多详细信息,请参阅此en.cppreference.com/w/cpp/utility/variant/variant(特别是第 7 个构造函数)。使用nested_list&lt;int&gt; 不会有歧义,因为int 不能从任何std::initializer_list&lt;T&gt; 构造,但对于某些其他类型可能会产生歧义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
相关资源
最近更新 更多