How to find an element using multiple search values ​​in C ++?

Conceptually, my data represents a table like this

+-------+------+------+------+------+  
|  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    |  
+-------+------+------+------+------+  

I am currently free to choose how this data will be saved. Essentially, I have identifiers with some values ​​that are assigned to identifiers. The set of values ​​is unique to the identifier (for another identifier, the set will not be repeated). Individual values ​​can be repeated by identifiers.

Now, what I need to do in C ++ is to find the name using a set of values. So something like this:

std::string findID(char val1, char val2, char val3, char val4)
{
    //Do something to find the corresponding Name

    return result;
}

, . , - . , , : unordered_map

, ?

+4
4

, , - ID/stringID. 5 char , .

+5

, - . char s, string std::unordered_map<std::string, std::string>, .

char s, . :

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 , , , . , , addRow . . , . , row1 3 table1, , , types . ID, types. - .

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 size == our table first index size
        if ( row.getSize() == rowSize_ ) {
            // This row 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 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;
}

, , , , , .

, , ; .

. ; . , .

... ...

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.

:

, . , , . ( ). .

, , , , .

, 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, addColumn. -, variadic TableRow, . , row's, .

Another thing to consider is that if each item in the list of data belonging to the identifier does not have the same type, this class should be slightly modified, instead of using it std::vector<T>you can use std::tuple<...>and compare two tuples from there.

+1
source

Alternatively, you can go with 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>();
    }
};
0
source

Source: https://habr.com/ru/post/1692648/


All Articles