有了域名之后怎么做自己的网站,提供零基础网站建设教学公司,wordpress企业模版配置,视频永久免费生成二维码一、数据的整合
在实际的开发场景中#xff0c;经常可以遇到以下的情况#xff1a;有几个地方的数据需要整合在一起。解决办法也有很多#xff0c;在不同的层面有不同的解决方式。比如经过清洗可以把非关系型数据转为关系型数据。但在底层编程的情况中会发现有几情况#…一、数据的整合
在实际的开发场景中经常可以遇到以下的情况有几个地方的数据需要整合在一起。解决办法也有很多在不同的层面有不同的解决方式。比如经过清洗可以把非关系型数据转为关系型数据。但在底层编程的情况中会发现有几情况 1、几个数组之间的合并。 当然前提是这些数组存储的数据是兼容的 2、几个容器间的合并 它们之间的KEY和VALUE也要有兼容的数据类型 3、混合合并 可能需要做一些简单的数据处理然后也可以合并在一起比如数组数据增加一个KEY可以利用索引就可以合并到容器中反过来也可以考虑。
其实上面列举这么几种本质就是把数据放到一个容器广泛意义上的容器中这样方便程序的处理。比如有两个List连接到一起一后就方便进行排序等算法的操作。
二、容器连接的基础方法
1、循环处理 这是最容易想到的方法
#include iostream
#include unordered_map
std::unordered_mapint, int unmap{{1, 100}, {2, 200}};
int insertMap(std::unordered_mapint, int map) {if (map.size() 1) {return 0;}for (auto [k, v] : map) {unmap.emplace(k, v);}return unmap.size();
}int main(void) {std::unordered_mapint, int map{{3, 300}, {4, 400}};size_t count insertMap(map);std::cout new map size: count std::endl;return 0;
}2、 std::merge 它有两种合并的接口一种是使用全局的merge一种是使用容器自身包含的
//map自身
#include iostream
#include map
#include stringint main()
{std::mapint, std::string ma{{1, apple}, {5, pear}, {10, banana}};std::mapint, std::string mb{{2, zorro}, {4, batman}, {5, X}, {8, alpaca}};std::mapint, std::string u;u.merge(ma);std::cout ma.size(): ma.size() \n;u.merge(mb);std::cout mb.size(): mb.size() \n;std::cout mb.at(5): mb.at(5) \n;for (auto const kv : u)std::cout kv.first , kv.second \n;
}
//全局
#include algorithm
#include iterator
#include list
template typename T void printList(const T con, const char *c) {std::copy(con.cbegin(), con.cend(), std::ostream_iteratortypename T::value_type(std::cout, c));std::cout std::endl;
}
void stdMergeList() {std::listint l1{0, 1, 6, 3, 9, 7};std::listint l2{16, 11, 18, 35, 66};std::listint l3{};std::merge(l1.begin(), l1.end(), l2.begin(), l2.end(), std::back_inserter(l3));printList(l3, );
}int main(void) {stdMergeList();return 0;
}上面的例程都比较简单一看就明白。不过需要注意的是有些小细节可能比较麻烦比如在上面的使用全局处理时如果插入到l2或l1中会是什么情况可以试试。
另外还有一种方式就是使用C17中的Node Handle的机制进行处理。
三、Node Handle
C17中的Node handle节点句柄其实更应该说是一种机制而非方法。它主要用来处理基于结点的数据结构常见的就是关联容器如map,set等。它可以用Node Handle句柄来处理未指定类型的对象提取的节点。先看一个cppreference上的例子
#include algorithm
#include iostream
#include string_view
#include unordered_mapvoid print(std::string_view comment, const auto data)
{std::cout comment;for (auto [k, v] : data)std::cout k ( v );std::cout \n;
}int main()
{std::unordered_mapint, char cont{{1, a}, {2, b}, {3, c}};print(Start:, cont);// Extract node handle and change keyauto nh cont.extract(1);nh.key() 4;print(After extract and before insert:, cont);// Insert node handle backcont.insert(std::move(nh));print(End:, cont);
}代码非常简单大家一看就明白了。
四、分析
如果使用上面基础的连接方法问题是没有什么大问题。但在实现上会有些让开发者不舒服的地方。比如循环方式插入看似简单明了但在底层大量进行了内存的分配和拷贝移动这会导致在某些情况下出现性能的瓶颈而使用merge虽然有些进步但并没有从本质解决同时它还引入了一些场景的限制。比如全局的情况就只能使用有序的容器。这些细节如果再遇到复杂的应用场景如多线程等情况一不小心可能就引入了错误。 而使用Node Handle就比较灵活方便由于其只是Move元素所以其效率和内存处理就简单和快捷许多。它利用了extract和insert函数指向性非常准确和明显即使出现异常也容易发现非常易于维护。正如前面所分析简单是王道 不过使用此种机制也要小心一些重复插入的问题文档说这种情况可能会产生UB行为。同时仍然如前面所讲合并的前后必须保证数据类型的一致性。最后切记切记STL的容器一般都是非线程安全的。
五、总结
其实编程就是从这些小的功能一点点的把基础打好的。正如前面的容器中的insert,push_back和后来的emplace_back。STL库中为什么要有这么多的方法来处理元素的插入把这些细节把握住就深刻明白了C中容器组织的过程。从另外一个角度打开学习的途径。 人生而有涯而学之也无涯