从概念上讲,我的数据代表了一个像这样的表
+-------+------+------+------+------+
| ID | Val1 | Val2 | Val3 | Val4 |
+-------+------+------+------+------+
| Name1 | a | b | c | d |
| Name2 | a | b | c | e |
| Name3 | h | b | c | d |
| Name4 | i | j | k | l |
+-------+------+------+------+------+
目前,我可以自由选择如何存储数据。基本上我有一些带有一些值的ID,这些值被分配给ID。一组值对于ID是唯一的(不会为另一个ID重复设置)。可以跨ID重复单个值。
现在,我需要在C ++中做的是使用一组值来查找名称。所以基本上是这样的:
std::string findID(char val1, char val2, char val3, char val4)
{
//Do something to find the corresponding Name
return result;
}
我目前对如何解决这个问题有点麻木不仁。我想过使用带有元组的映射,但为元组提供哈希函数似乎使问题过于复杂。所以基本上就像这里描述的那样:Using tuple in unordered_map
我似乎忽视了一个更简单的解决方案吗?
答案 0 :(得分:5)
如果所有值都是字符,我认为你最好将表的每一行转换为字符串,并为这对夫妇ID / stringID提供一个哈希表。当您获得5个值作为char来测试您时,只需将它们连接起来并运行搜索。
答案 1 :(得分:2)
是的,最简单的方法是存储从元组值到名称的映射。但是,如果您的值为char
s,那么最简单地使用string
并将所有内容打包到std::unordered_map<std::string, std::string>
中,关键是将所有值打包到字符串中,以及你的名字的价值。
如果您的价值不是char
,那么它仍然不那么复杂。您可以只使用结构,而不是使用元组:
struct Key {
std::array<Value, n> vals;
};
然后提供std::hash
个实例,以boost::hash_combine
折叠数组:
class KeyHash {
std::size_t operator()(Key const& k)
{
std::size_t h = 42;
for (Value const& v : k.vals) {
boost::hash_combine(h, v);
}
return h;
}
};
您已经链接的问题和提供的解决方案也不是很糟糕,并且通用性足以放入一些可重用的库中。
答案 2 :(得分:1)
您的数据表中似乎有1对多的关系,因为我们知道可以创建一个表示任意行的简单类。从那里我们可以创建另一个简单的类,它从构造函数中获取一行,它还有一个addRow方法来添加额外的行。行没有限制。该表仅限于传入的第一行的大小。因此,如果row1
有3个元素并传递给table1
的构造函数,则添加到此实例化表的每隔一行必须具有相同的types
和大小。这些类集是ID
&amp;的模板。 Types
。以下是基本声明 - 这些类的定义&#39;结构。
template<class ID, class Type>
class TableRow {
private:
ID id_;
std::vector<Type> values_;
public:
template<class... Params>
TableRow( const ID& id, Params&&... valuePack ) :
id_( id ),
values_ { std::forward<Params>( valuePack )... }
{}
ID getID() const {
return id_;
}
std::vector<Type> getValues() const {
return values_;
}
std::size_t getSize() const {
return values_.size();
}
};
template<class ID, class Type>
class Table {
private:
std::size_t rowSize_;
std::vector<TableRow<ID, Type>> table_;
public:
explicit Table( TableRow<ID, Type> row ) {
table_.push_back( row );
rowSize_ = row.getSize();
}
void addRow( TableRow<ID, Type> row ) {
// Check to see if row's size == our table's first index size
if ( row.getSize() == rowSize_ ) {
// This row's size is a match and this row of data is compatabile with our current table
table_.push_back( row );
} else {
std::ostringstream strStream;
strStream << __FUNCTION__ << " row passed in does not match size of this table's row size." << std::endl;
throw std::exception( strStream.str().c_str() );
}
}
// methods to retrieve a row, an id, or a specific element to an id,
// comparison operators, ostream friend operators etc. here...
};
这是一个实例化它们的例子......
int main() {
try {
std::string id = std::string( "John" );
std::string val1 = std::string( "a" ), val2 = std::string( "b" );
std::string val3 = std::string( "c" ), val4 = std::string( "d" );
TableRow<std::string, std::string> tr1 { id, val1, val2, val3, val4 };
Table<std::string, std::string> table( tr1 );
TableRow<std::string, std::string> tr2( "Mike", "e", "f", "g", "h" );
table.addRow( tr2 );
TableRow<std::string, std::string> tr3( "Susan", "a", "b", "c" );
//table.addRow( tr3 ); // exception thrown
TableRow<unsigned, float> trf1( 0, 2.3f, 4.5f );
TableRow<unsigned, float> trf2( 1, 4.5f, 7.8f );
Table<unsigned, float> table2( trf1 );
table2.addRow( trf2 );
TableRow<unsigned, float> trf3( 2, 3.5f, 8.7f, 9.2f, 4.8f );
//table2.addRow( trf3 ); // exception thrown
//table.addRow( trf3 ); // will not compile - mismatched TYPES
} catch ( std::exception e ) {
std::cout << e.what() << std::endl;
std::cout << "\nPress any key and enter to quit." << std::endl;
char q;
std::cin >> q;
return -1;
}
std::cout << "\nPress any key and enter to quit." << std::endl;
char q;
std::cin >> q;
return 0;
}
如果您取消注释任何一条表示将抛出异常的行,您可以看到该表如何捕获不同行大小的不匹配,因为它们的长度必须相等。
比较,查找,显示该表的功能;我将此作为一项持续的练习。
但是我可以给你一些指导。现在,根据整行或一组数据查找ID;这应该很简单。您必须将一个向量与另一个向量进行比较,然后返回该ID。
但是这有问题......以下是问题的一个例子......
IDs | val1, val1, val3, val4
1 | a b c d
2 | e f g h
3 | a b c d
如果我们正在搜索具有(a,b,c,d)
集合的此表格,请执行此操作。有2
种可能的解决方案。因此,您无法直接返回单个答案或单个ID
,因为这是一个X|Y
问题,但是因为我们在这种情况下有一个很好的vectors
而不是返回一个答案您可以将set
个答案返回到有效rows
或row - ids
的容器中,但要执行此操作,您必须搜索整个表格,并且每个表格都匹配一次必须将它推入一个临时容器,直到找到所有匹配,然后返回该容器,如果只有一个匹配,你仍然会返回一个容器,但它只包含一个元素,因为它只是一组1
。
但是你确实提到了这个:
目前,我可以自由选择如何存储数据。基本上我有一些带有一些值的ID,这些值被分配给ID。一组值对于ID是唯一的(不会为另一个ID重复设置)。可以跨ID重复单个值。
因此,如果已经存在的数据没有出现这个问题,那么它就不应该引起关注。
因此,您的搜索将来自Table
的
template<class ID, class Type>
ID Table<ID, Type>::find( const std::vector<Type>& data ) {
for ( auto& row : table_ ) {
if ( data == row.getValues() ) {
return row.getId();
} else {
std::ostringstream strStream;
strStream << __FUNCTION__ << " could not find matching set." << std::endl;
throw std::exception( strStream.str().c_str() );
}
}
}
对于上面的课程,您甚至可以扩展它们,以便在需要时增加表格的大小。
您必须向addItem
类模板添加addElement
或TableRow
方法,然后在Table
类模板中添加addColumn
1}}方法,addColumn
方法会有两个技巧。第一个是variadic
和TableRow
的构造函数一样,但元素的大小必须等于表中的行数。另一个技巧是必须将参数包中的每个元素附加到表中的每个单独的行,但是此函数还必须更新row's
大小,这不应该是那么难做到的。
要考虑的另一件事是,如果属于ID的数据列表中的每个元素的类型不同,则必须稍微修改这些类,而不是使用{{ 1}}你可以使用std::vector<T>
并从那里比较两个元组。
答案 3 :(得分:0)
作为替代方案,您可以使用std::vector<std::tuple<std::string, char, char, char, char>>
:
struct somestruct
{
std::vector<std::tuple<std::string, char, char, char, char>> _data;
std::string findID(char val1, char val2, char val3, char val4)
{
auto it = std::find(begin(_data), end(_data) [](const auto& item) {
return item.get<1>() == val1 && /*...*/;
});
return it->get<0>();
}
};