如何在C ++中实现等效的嵌套Perl哈希?

时间:2010-08-30 14:10:07

标签: c++ perl stl

我想将一些Perl代码更改为C ++。我需要知道如何在C ++中实现嵌套的Perl哈希。我认为STL是一个不错的选择,并使用了地图。借助map,我只能创建一个简单的hash,但我不知道如何创建嵌套的hash结构。

我的Perl哈希是这样的:

%foo = (
    "bar1" => {
        Default => 0,
        Value   => 0
    },
    "bar2" => {
        Default => 2,
        value   => 5,
        other   => 4
    }
)

我可以这样修改它:$foo{"bar1"}->{"Default"} = 15

如何使用STL在C ++中执行此操作?也许这是一个简单的问题,但我无法弄明白。

5 个答案:

答案 0 :(得分:4)

您可能需要以下类型:

std::map< std::string, std::map<std::string, int> > 

您可能需要使用struct(或class)代替。

struct Element {
    int default;
    int value;
    int other;
    Element(): default(0), value(0), other(0)
    { }
    Element(int default_, int value_, int other_)
    : default(default_)
    , value(value_)
    , other(other_)
    { }
};

int main() {
    std::map<std::string, Element> elements;
    elements["bar1"]; // Creates element with default constructor
    elements["bar2"] = Element(2,5,4);
    elements["bar3"].default = 5; // Same as "bar1", then sets default to 5
    return 0;
}

答案 1 :(得分:2)

您可以使用std::map<key_t,std::map<key_t,value_t> >嵌套哈希。

答案 2 :(得分:2)

正如Steve Townsend所指出的,std::map在概念上是相似的,但具有不同的实现。

在C ++中创建嵌套容器有点冗长:

#include <tr1/unordered_map>
#include <iostream>

typedef std::tr1::unordered_map< std::string, int >   Inner;
typedef std::tr1::unordered_map< std::string, Inner > Outer;

int main()
{
  Outer foo;

  Inner::value_type bar1_data[] = {
    Inner::value_type("Default", 0),
    Inner::value_type("Value",   0),
  };
  const size_t n_bar1_data = sizeof(bar1_data) / sizeof(*bar1_data);

  foo["bar1"] = Inner(bar1_data, bar1_data + n_bar1_data);

  Inner::value_type bar2_data[] = {
    Inner::value_type("Default", 2),
    Inner::value_type("value",   5),
    Inner::value_type("other",   4),
  };
  const size_t n_bar2_data = sizeof(bar2_data) / sizeof(*bar2_data);

  foo["bar2"] = Inner(bar2_data, bar2_data + n_bar2_data);

perlref中所述,下标括号之间的箭头是可选的,因此您可以编写(注释以维护C ++程序的流程)

  // $foo{"bar1"}{"Default"} = 15;

非常接近C ++:

  foo["bar1"]["Default"] = 15;

为了更好地衡量,我们打印结果结构并从main返回0:

  for (Outer::const_iterator o = foo.begin(); o != foo.end(); ++o) {
    std::cout << o->first << ":\n";
    for (Inner::const_iterator i = o->second.begin(); i != o->second.end(); ++i)
      std::cout << "  - " << i->first << " => " << i->second << '\n';
  }

  return 0;
}

输出:

bar1:
  - Value => 0
  - Default => 15
bar2:
  - Default => 2
  - value => 5
  - other => 4

注意:此玩具程序中的输入和输出具有相同的顺序,但不依赖于此行为!

如果您更喜欢使用boost::unordered_map,请在程序顶部更改几行:

#include <boost/unordered_map.hpp>

typedef boost::unordered_map< std::string, int >   Inner;
typedef boost::unordered_map< std::string, Inner > Outer;

答案 3 :(得分:0)

让我在问题中添加一些元信息。其他人提供了实际的工作代码样本。

除了是一种不同类型的容器(O(对于C ++映射的log(n)访问与通常为Perl哈希的O(1)),C ++映射和Perl哈希之间的主要区别在于静态与动态语言本身的类型区别。映射的模板参数清楚地指定键和值的类型,而对于Perl哈希,只有键具有已知类型(字符串)。值是标量,但是可以且通常包含任何类型的数据结构。因此,将C ++映射用于相当普通的Perl数据结构是非常麻烦的,例如:

{
  foo => [qw(bar baz)],
  quibble => {
    lion => 'animal',
    pine => 'plant',
  },
  count => 5,
}

这是一个实际的区别而不是概念区别,因为你总是可以定义一个包含任意内容的结构/类/类型(参见其他答案)。这只是更多的工作,最终使用起来非常麻烦。

只有在数据结构非常规则的情况下,才能使用map<string, map<string, Stuff> >这样的简单模板类型。

答案 4 :(得分:0)

  

如何使用STL在C ++中执行此操作?也许这是一个简单的问题,但我无法弄明白。

使用Perl哈希的方式是模仿C / C ++ struct的常用方法。

因此,我认为代码最接近的C ++转换是:

struct foobar {
   int Default, value, other;

   foobar(int Default_ = 0, int value_ = 0, int other_ = 0)
     : Default(Default_), value(value_), other(other_)
   {}
};

std::map< std::string, foobar > foo;

foo["bar1"] = foobar( 0, 0 );
foo["bar2"] = foobar( 2, 5, 4 );