Best Way to Find the Array Contains a Given String - c++

I have some arrays of strings and a function that gets a string and return the type of it (the array that the string belongs to)
How can I do it with the best speed?
string arr1[] = {"a", "b", "c"};
string arr2[] = {"d", "e", "f"};
string arr3[] = {"g", "h", "i"};
string arr4[] = {"j", "k", "l"};
...
string getFamily(string input)
{
if(arr1.contains(input)
return "TYPE_1";
...
}
Thanks

This is not elegant, but if you want fast, you can make a prepared unordered_map to do the search which would be useful if this function will be called 100s of times (wasteful if rarely called). Ideally, you can make this container in a class object rather than a global variable and the return type an integral value rather than a string. This would produce a search of O(1) with the cost being in the hashing of the key. But I do not know enough of your requirements.
If you would rather call once, then do as Joachim Pileborg suggested and do a series of std::find calls until you get a hit.
#include <iostream>
#include <unordered_map>
#include <string>
std::unordered_map< std::string, std::string > g_map;
std::string arr1[] = {"a", "b", "c"};
std::string arr2[] = {"d", "e", "f"};
std::string arr3[] = {"g", "h", "i"};
std::string arr4[] = {"j", "k", "l"};
const char * map_value( const std::string & input )
{
std::unordered_map< std::string, std::string >::iterator iter( g_map.find( input ) );
return iter == g_map.end() ? "NOT FOUND" : iter->second.c_str();
}
int main( int argc, char ** argv )
{
// Build the map;
for( int i = 0; i < sizeof( arr1 ) / sizeof( std::string ); ++i )
g_map[arr1[i]] = "TYPE_1";
for( int i = 0; i < sizeof( arr2 ) / sizeof( std::string ); ++i )
g_map[arr2[i]] = "TYPE_2";
for( int i = 0; i < sizeof( arr3 ) / sizeof( std::string ); ++i )
g_map[arr3[i]] = "TYPE_3";
for( int i = 0; i < sizeof( arr4 ) / sizeof( std::string ); ++i )
g_map[arr4[i]] = "TYPE_4";
std::string input;
std::cout << map_value( "b" ) << std::endl;
std::cout << map_value( "z" ) << std::endl;
std::cout << map_value( "eb" ) << std::endl;
std::cout << map_value( "j" ) << std::endl;
std::cout << map_value( "f" ) << std::endl;
return 0;
}
Output:
TYPE_1
NOT FOUND
NOT FOUND
TYPE_4
TYPE_2

Related

Recursive Function that returns all substrings of a string

I need to implement a function in C++,
vector<string> generateSubstrings(string s),
that returns a vector of all substrings of a string. For example, the substrings of the string “rum” are the seven strings
“r”, “ru”, “rum”, “u”, “um”, “m”, “”.
The function has to be recursive and has to return the results as a vector.
Here is my code so far. It's only printing "r", "ru" and "rm". I'm having alot of trouble implementing this function. I've been working on this for the past few hours but I just can't figure out how to get it working as stated, so any help would be appreciated.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> generateSubstrings(string s, int num){
int index = num;
int SIZE = s.size();
vector<string> substrings;
if(index == s.size()){//BASE CASE
string temp = s.substr(index,1);
substrings.push_back(temp);
}
else{
for(int i = 0; i < SIZE; ++i){
string temp = s.at(index) + s.substr(i,i);
substrings.push_back(temp);
}
generateSubstrings(s, num + 1);
}
return substrings;
}
int main() {
vector<string> vec(20);
vec = generateSubstrings("rum", 0);
cout << endl << endl;cout << "PRINTING VECTOR" << endl;
for ( int i = 0; i<vec.size();++i){
cout << vec.at(i);
cout << endl;
}
cout << "DONE";
}
In your assignment there is written that the recursive function has to be declared like
vector<string> generateSubstrings(string s),
But you are trying to make another function recursive that declared like
vector<string> generateSubstrings(string s, int num);
So in any case your solution does not satisfy the requirement of the assignment.
The function can look the following way
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
for ( const std::string &t : generateSubstrings( s.substr( 1 ) ) )
{
v.push_back( t );
}
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Its output is
r
ru
rum
u
um
m
If you need also to include an empty string then you should change condition
if ( s.empty() ) return {};
in appropriate way. For example
if ( s.empty() ) return { "" };
Also in this case you should write
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
Also you can replace the loop in the shown function with method insert. For example
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
The program output will be the same as shown above.
Here is a program modification that includes an empty string in the vector.
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return { "" };
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Here's an answer using Python. It prints the correct result for "rum", but for "rumm" it prints two "m" substrings for obvious reasons:
def substrings(s):
result = []
if len(s) == 0:
result.append("")
if len(s) > 0:
result += substrings(s[1:])
for n in range(1,len(s)+1):
result.append(s[0:n])
return result
print substrings("rum")
print substrings("rumm")
The idea of the algorithm is the following: for "rum", the substrings are the substrings of "um" followed by "r", "ru" and "rum". For "um", the substrings are the substrings of "m" followed by "u" and "um". For "m", the substrings are the substrings of "" followed by "m". For "", the substrings are simply "". So, the final list is "", "m", "u", "um", "r", "ru", "rum".
Although this isn't C++, you should be able to translate the code to C++. But that may not necessarily be what you want as "rumm" has two "m" substrings. If you think that "rumm" should have only one "m" substring, please leave a comment and I'll post another answer.
First, you should pay attention about code indent.
Then, I don't look your code, I wrote some code to achieve your aim, as follow:
void generateSubstrings(string s, int num, vector<string> &sta)
{
if (num == s.size())
return;
auto b = begin(s) + num;
string temp = "";
temp += *b;
sta.push_back(temp);
b++;
while (b != end(s))
{
temp += *b;
sta.push_back(temp);
b++;
}
generateSubstrings(s, num + 1, sta);
}

Find an element in vector<vector<string>>

I store this file in vector<vector<string>>:
1 a aa # vector of string stored to `vector<vector<string>>`
2 b bb
3 c cc # c -> index == 2
4 d dd
C++ code:
vector<vector<string>> myvect =
{{"1","a","aa"},
{"2","b","bb"},
{"3","c","cc"},
{"4","d","dd"}};
How can I search for c in the second column and get its index (I know it is in the second vector) - the output should be 2.
I want to use find or find_if function.
If you specificially want to search the 2nd column of the inner vector you can use a transform_iterator and regular find.
transform_iterator is in boost would look something like:
std::vector< std::vector< std::string > > v;
auto lambda = [] ( std::vector< std::string > const& v ) { return v[1]; };
auto transform_end = boost::make_transform_iterator ( v.end() );
return std::find( boost::make_transform_iterator( v.begin(), lambda ),
transform_end, "c" ) != transform_end;
If your inner lambda is to find "c" in any position I wouldn't use transform iterator here as we want to return a true/false on each inner vector, not just some transformed value, and we would use find_if on the outer-vector and find on the inner one
std::string val = "c";
auto lambda = [ const & ]( std::vector< std::string > const& vInner )
{ return std::find( vInner.begin(), vInner.end(), val ) != v.end(); } ;
return std::find_if( v.begin(), v.end(), lambda );
You can try something similar to the code below
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<std::vector<std::string>> v =
{
{ "1", "a", "aa" },
{ "2", "b", "bb" },
{ "3", "c", "cc" },
{ "4", "d", "dd" }
};
std::vector<std::string>::iterator second;
std::string s = "c";
auto first = std::find_if( v.begin(), v.end(),
[&]( std::vector<std::string> &v1 )
{
return (( second = std::find( v1.begin(), v1.end(), s ) ) != v1.end() );
} );
if ( first != v.end() )
{
size_t i = std::distance( v.begin(), first );
size_t j = std::distance( v[i].begin(), second );
std::cout << v[i][j] << std::endl;
}
return 0;
}
The output is
c
You can do this:
int column = 1; // Set this to the column you need to search;
string target( "c" ); // Set this to the value you need to find
auto found = find_if( myvect.begin(), myvect.end(), [=]( vector< string > row ){ return row[column] == target; } );
cout << ( found == myvect.end() ? "not found" : ( *found2 )[column] ) << endl;
C++11 wont let you define column or target in the capture, if you want to avoid intermediate variables in C++11 though, you can do this, it's just ugly cause of the static_cast. You'd just have to set the "c" and 1 to the target and column:
auto found = find_if( myvect.begin(), myvect.end(), bind( equal_to< string >(), "c", bind( static_cast< const string&( vector<string>::* )( size_t ) const >( &vector< string >::operator[] ), placeholders::_1, 1 ) ) );
I personally would suggest that if your row size is always the same that you put it in a single std::vector like this: vector<string> myvect = { "1", "a", "aa", "2", "b", "bb", "3", "c", "cc", "4", "d", "dd" }; if you do that you can write a template to search for you which will have significantly more flexibility:
template< typename T, int stride >
T* templateFind( const vector< T >& myvect, const T& target, int column )
{
typedef array< T, stride > rowSize;
rowSize* end = ( rowSize* )( &*( myvect.begin() ) ) + ( myvect.size() / stride );
rowSize* result = find_if( ( rowSize* )( &*( myvect.begin() ) ), end, [&]( rowSize row ){ return row[column] == target; } );
return result == end ? nullptr : ( ( T* )result ) + column;
}
And use it like this:
string* found = templateFind< string, 3 >( myvect, "c", 1 );
cout << ( found == nullptr ? "not found" : *found ) << endl;

How to create a new vector with particular columns from existing 2D vector in c++

I have 2D Vector (vector<vector<string>>) with a lot of columns (m*n) (Here I mentioned this 2D Vector as Maintable). I want to create a new vector with a few particular columns from main table.
For Example, Suppose If I have a main table with 12 columns, I want to take any 3 Non Contiguous columns from the main table into new 2D Vector. How to do that?
You can use something as the following
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
//...
const size_t N = 10;
std::string a[] = { "A", "B", "C", "D", "E", "F" };
std::vector<std::vector<std::string>> v1( N, std::vector<std::string>( std::begin( a ), std::end( a ) ) );
std::vector<std::vector<std::string>> v2;
v2.reserve( v1.size() );
for ( const std::vector<std::string> &v : v1 )
{
v2.push_back( std::vector<std::string>(std::next( v.begin(), 2 ), std::next( v.begin(), 5 ) ) );
}
for ( const std::vector<std::string> &v : v2 )
{
for ( const std::string &s : v ) std::cout << s << ' ';
std::cout << std::endl;
}
It is simple to rewrite the code using the C++ 2003 syntax. For example you can write
std::vector<std::vector<std::string>> v1( N,
std::vector<std::string>( a, a + sizeof( a ) / sizeof( *a ) ) );
instead of
std::vector<std::vector<std::string>> v1( N, std::vector<std::string>( std::begin( a ), std::end( a ) ) );
and so on.
EDIT: If the columns are not adjacent then you can use the following approach
#include <iostream>
#include <vector>
#include <array>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 10;
const size_t M = 3;
std::string a[N] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
std::vector<std::vector<std::string>> v1( N, std::vector<std::string>( std::begin( a ), std::end( a ) ) );
std::vector<std::vector<std::string>> v2;
v2.reserve( v1.size() );
std::array<std::vector<std::string>::size_type, M> indices = { 2, 5, 6 };
for ( const std::vector<std::string> &v : v1 )
{
std::vector<std::string> tmp( M );
std::transform( indices.begin(), indices.end(), tmp.begin(),
[&]( std::vector<std::string>::size_type i ) { return ( v[i] ); } );
v2.push_back( tmp );
}
for ( const std::vector<std::string> &v : v2 )
{
for ( const std::string &s : v ) std::cout << s << ' ';
std::cout << std::endl;
}
}

Iterate elements of array using pointer

I try execute code:
char* m[3] = {"123", "456", "789"};
for(char* st=*m; st!=0; st=*(m+1))
{
cout <<st;
}
but it hung up and print: 123456456456...
The loop you wrote is invalid
char* m[3]={"123","456","789"};
for(char* st=*m;st!=0; st=*(m+1))
{
cout <<st;
}
Expression *m has type char * and array m does not contain NULL pointer. So condition st!=0;
is wrong. And the pointer always will point the same element because expression st=*(m+1) gives always the second element of the array
Also take into account that the correct definition of the array will be
const char* m[3] = { "123", "456", "789" };
because it is an array of pointers to string literals and string literals may not be changed.
You could use simply the range based for statement
const char* m[3] = { "123", "456", "789" };
for ( const char* st : m )
{
cout <<st << std::endl;
}
Or you could use iterators in the loop. For example
const char* m[3] = { "123", "456", "789" };
for ( auto it = std::begin( m ); it != std::end( m ); ++it )
{
cout << *it << std::endl;
}
And you could use standard algorithm std::copy
#include <iostream>
#include <algorithm>
#include <iterator>
//,,,
const char* m[3] = { "123", "456", "789" };
std::copy( std::begin( m ), std::end( m ),
std::ostream_iterator<const char *>( std::cout, "\n" ) );
Stop using char* for strings immediately and start using std::string. The same goes for C-style arrays: start using std::array or std::vector. This will save you years of your life and unnecessary pain.
Just look at how beautiful this code is:
std::array<std::string, 3> m = {"123", "456", "789"};
for (auto& s : m)
std::cout << s;
and here's the live example.
Using the code you provided here is one way of doing it:
const char* m[3]={"123","456","789"};
const unsigned int element_count = sizeof(m) / sizeof(m[0]);
//not a nice to have sizeof here, but i used this to keep the code
// consistent with the code provided in the question
for( const char** st = m; st!= (m + element_count) ; st ++ )
{
cout << *st;
}
As you can see to iterate trough an array of char* elements you need to use a pointer to char* and therefore the type is char ** for the iteration variable st.
The code you has was an infinite loop because you assigned st with *(m+1) which is never equal to 0, in fact it's the second element every time.
However there are safer ways of using doing this, by using a std::vector for example:
std::vector<std::string> m = {"123", "456", "789"};
for (auto& st : m)
std::cout << st;
//or:
for(std::vector<std::string>::iterator i = m.begin(),e = m.end();i != e;i++)
std::cout << *i;
//or:
for(std::size_t i = 0;i < m.size() ;i++)
std::cout << m[i];
The problem is that you point a pointer to the same location in each iteration:
char* m[ 3]={ "123","456","789"};
for( char* st = *m; st != 0; st = *( m + 1))
// ^^^^^^^^^ <- this doesn't change,
// st points to *(m+1)
{
std::cout << st;
}
Also you should not use a non-const char * to point to a nonmodifiable string literal:
const char* m[ 3]={ "123","456","789"};
const unsigned int n = sizeof( m) / sizeof( m[ 0]);
for( const char** st = m; st != (m + n) ; st ++ )
{
cout << *st;
}
Even range - based iteration will work:
const char* m[ 3] = { "123", "456", "789" };
for ( const char* st : m )
{
std::cout << st << std::endl;
}
If for some reason you have to stick to simple iteration, this will also work:
const char* m[ 3]={ "123","456","789"};
const char* st;
int r = 0;
for( st = *m; r < 3; st = *( m+r))
{
std::cout << st << std::endl;
r++;
}
Please consider using a standard container, i.e std::vector or std::array. It will help you a lot, mainly in dynamic memory management.
std::vector< std::string> v = { "123", "456", "789"};
for ( auto& s : v)
std::cout << s;
This is the least intrusive solution:
char* m[4] = {"123", "456", "789", NULL};
for(char** st=m; *st!=0; st=(st+1))
{
cout <<*st;
}

Does C++ have a sequential search function?

I have a small unsorted array and I'd like to find the index of a particular value. Does C++ have a built-in sequential search function for this, or do you just write the loop yourself each time it comes up?
I'm specifically using a C-style array like:
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
and I need the index of a value that the user supplies.
Use std::find() from the STL-algorithm-library, or the find()-method of your particular container.
std::find() should work:
#include <stdio.h>
#include <algorithm>
#include <string>
using std::string;
std::string arr[5] = { "EVEN", "ODD", "NONE", "MARK", "SPACE" };
int main() {
string* pArrEnd = arr + sizeof( arr)/sizeof(arr[0]);
string* pFound = std::find( arr, pArrEnd, "MARK");
if (pFound == pArrEnd) {
printf( "not found\n");
}
else {
printf( "%s was found at index %d\n", pFound->c_str(), pFound - arr);
printf( "or using STL: %d\n", std::distance( arr, pFound));
}
return 0;
}
You can use STL algos on containers other than just STL containers. For example, you can std::find() in a C-style array:
// alloc the array
static const size_t numItems = 100000;
int * items = new int[numItems];
// fill the array
for( size_t n = 0; n < numItems; ++n )
items[n] = n;
// find 42 using std::find()
int* found = std::find(&items[0], &items[numItems], 42);
if( found == &items[numItems] )
{
// this is one past the end, so 42 was not found
items[0] = 42;
}
else
{
// we found the first instance of 42 at this location
// change it to 43
*found = 43;
}
I suppose you need the index and not the iterator.
int main()
{
// for c++ vector
typedef int Element;
typedef std::vector<Element> CppVector;
CppVector v;
v.push_back( 2 );
v.push_back( 4 );
v.push_back( 8 );
v.push_back( 6 );
const Element el = 4;
CppVector::const_iterator it = std::find( v.begin(), v.end(), el );
if ( it == v.end() )
{
std::cout << "there is no such element" << std::endl;
}
else
{
const CppVector::size_type index = it - v.begin();
std::cout << "index = " << index << std::endl;
}
// for C array
typedef Element CVector[4];
CVector cv;
cv[0] = 2;
cv[1] = 4;
cv[2] = 8;
cv[3] = 6;
const std::size_t cvSize = sizeof( cv ) / sizeof( Element );
std::cout << "c vector size = " << cvSize << std::endl;
const Element* cit = std::find( cv, cv + cvSize, el );
const std::size_t index = cit - cv;
if ( index >= cvSize )
std::cout << "there is no such element" << std::endl;
else
std::cout << "index = " << index << std::endl;
}
In addition to the STL possibility (std::find) already mentioned there is the POSIX function lsearch (with c semantics).