【问题标题】:Dynamic multi-dimensional array with key in C++C++中带键的动态多维数组
【发布时间】:2020-04-30 21:02:08
【问题描述】:

我正在尝试找到一种在 C++ 中处理以下场景的好方法。

当我们在服务器上启动服务时,会根据数据库中的数据初始化如下的参数表。

ID, filed_1, field_2, .... , field 50
100abc, ***, ***, ...., ***
120def, ***, ***, ...., ***
...
...
500xyz, ***, ***, ..., ***

字段/列:大约 50 个。字段的数量和格式是固定的。所有字段的类型都是 int、double 或 char*(不是很长的 char*)。

Records/rows:最多200条。根据数据,每次记录的数量会有所不同。

ID 是唯一的。

在计算过程中,会以每秒500次的速度读取和更新参数表。 (我假设按 id 和字段名称搜索)

低延迟在系统中很重要。

在这种情况下最好使用什么数据结构?

如果有没有写(更新)操作可以大大提高效率的方法,也请分享信息。 我认为有一些解决方法可以不更新参数表。

非常感谢。

【问题讨论】:

  • 对于固定数量的列,我会使用(一维)std::vector<>。如果列数不同,可以使用 std::vector<std::vector> 代替。对于每一行:如果某些列具有固定类型,我将使用 struct 对行数据进行建模。 struct 可能包含一个 std::vector<>(或 std::array)成员,用于重复相同类型的列。如果您通常不知道某些列是否包含数字(带或不带小数点)或文本,那么我会将它们全部存储为std::stringstd::any<std::string, double, int> 可能是一个替代方案,但我不确定它是否值得。
  • 抱歉,为什么是json 标签?如图所示,您的输入数据看起来像一个 CSV 文件:SO: How can I read and parse CSV files in C++?
  • 谁在更新您的表格?为什么要每秒将其存储在磁盘上 500 次?使用内存映射消息传递解决方案不是更好吗?

标签: c++ json dictionary vector hash


【解决方案1】:

仅供参考,您是在问一个关于算法和数据结构的固执己见的问题,这通常更适合这个堆栈交换网站: https://softwareengineering.stackexchange.com/

不管怎样,带着所有适当的盐粒,这是我不知情的意见。考虑到这一点:

字段的计数和格式是固定的。

还有这个:

低延迟在系统中很重要。

考虑使用具有完美散列函数的散列映射来按名称查找字段。过去,您会使用 gperf 作为构建步骤以在 C 中生成散列函数,但使用 C++ constexpr 魔法,您可以选择:

https://github.com/Kronuz/constexpr-phf

那里的文档实在是太无用了,所以这就是你如何使用它。首先输入您的字段以生成哈希函数:

fnv1ah32 fnv1a{};
constexpr auto fields_phf = phf::make_phf({
    fnv1a("field1"), 
    fnv1a("field2"), 
    fnv1a("field3"), 
    fnv1a("field4")
    /* , ... */
});

我对值使用什么没有任何特别的见解,但由于您想存储 3 种类型中的一种,我将在此示例中使用 std::variant

// ...assuming your field values will fit in std::string's short string optimization
using Value = std::variant<int, double, std::string>;

然后你可以围绕一个连续的数据数组包装一个 O(1) 查找表:

struct Row {
    std::array<Value, FIELD_COUNT> fields;

    template <typename T>
    Value& operator [](T&& t) { 
        auto pos = fields_phf.find(fnv1a(t));
        if (pos == phf::npos) {
            throw std::runtime_error("unknown field");
        }
        return fields[pos];
    }
};

然后使用常规哈希表查找行,如果您事先不知道值,这是一个很好的默认值。保留 200 行以尽量减少重新散列,因为您认为这是您的上限:

std::unordered_map<std::string, Row> table;
table.reserve(200);

然后您可以进行查找:

int main() {
table["row1"]["field1"] = 42;
table["row2"]["field2"] = "hello";

演示:https://godbolt.org/z/z8euVY

【讨论】:

  • 我意识到我有另一个我以前不知道的数据使用情况。基于同一列的数据会有很多计算。我做了一些搜索,似乎如果我使用地图/哈希图等,如果我想从一列中获取数据,我必须迭代所有行来获取数据。是正确的理解吗?是否有其他好的建议可以快速读取一列中的所有数据?
  • 退一步,每秒500次访问并不是很苛刻。地图基准测试通常以每秒数十万到数百万次访问来衡量,即使在较旧的系统上也是如此。您确定带有pair&lt;string, string&gt; 键的标准unordered_map,或者地图的地图不能很好地满足您的目的(需要维护的代码更少)?
猜你喜欢
  • 2012-02-02
  • 1970-01-01
  • 2018-05-16
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多