Hello, all,
This is probably not so much related to C++ (Sorry in advance). But
I did get this question during a C++ job interview.
You are asked to design some data structure and algorith for the
following function:
List getNames ( List nameList, String prefix );
What it does is: given a name list and a prefix, return all the
names in the name list that start with prefix.
For example, if nameList = { "abc", "abdf", "cde" } and prefix =
"ab", the function should return { "abc", "abdf" }.
I did not do well on that question. But I would like to see some
good designs.
Thanks a lot,
Nan
Here is a simple linear search:
#include <string>
#include <list>
#include <algorithm>
#include <functional>
#include <iterator>
#include <iostream>
template < typename RangeOne, typename RangeTwo >
bool is_prefix ( RangeOne pattern, RangeTwo text ) {
if ( text.size() < pattern.size() ) {
return( false );
}
return( pattern.end()
==
std::mismatch
( pattern.begin(), pattern.end(), text.begin() ).first );
}
// this really should be in std
template < typename IterIn, typename IterOut, typename Predicate >
IterOut copy_if ( IterIn from, IterIn to, IterOut where, Predicate p ) {
while ( from != to ) {
if ( p( *from ) ) {
*where = *from;
++where;
}
++from;
}
return( where );
}
typedef std::string String;
typedef std::list< String > List;
List getNames ( List const & nameList, String const & prefix ) {
List result;
copy_if( nameList.begin(), nameList.end(),
std::back_inserter( result ),
std::bind1st(
std:
tr_fun( is_prefix< String, String > ), prefix ) );
return( result );
}
int main ( void ) {
List l;
l.push_back ( String( "abcd" ) );
l.push_back ( String( "acd" ) );
l.push_back ( String( "abcd" ) );
l.push_back ( String( "acd" ) );
l.push_back ( String( "ab" ) );
l.push_back ( String( "abcd" ) );
l.push_back ( String( "ac" ) );
l.push_back ( String( "ab" ) );
l.push_back ( String( "abx" ) );
String p = "ab";
l = getNames( l, p );
std::copy( l.begin(), l.end(),
std:
stream_iterator< String >( std::cout, "\n" ) );
}
Here is something that might pay if searches for different prefixes are done
but the list ist not changed:
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
typedef std::string String;
typedef std::vector< String > List;
std::string succ ( std::string str ) {
while ( str.size() > 0 ) {
++ *str.rbegin();
if ( 0 == *str.rbegin() ) {
str.erase( str.size() - 1 );
} else {
break;
}
}
return( str );
}
List getNames ( List const &nameList, String prefix ) {
// this one assumes the list to be sorted
List::const_iterator from
= std::lower_bound( nameList.begin(), nameList.end(), prefix );
prefix = succ( prefix );
List::const_iterator to
=
prefix.size() > 0 ?
std::lower_bound( nameList.begin(), nameList.end(), prefix )
:
nameList.end();
List result;
std::copy( from, to, std::back_inserter( result ) );
return( result );
}
int main ( void ) {
List l;
l.push_back ( String( "abcd" ) );
l.push_back ( String( "acd" ) );
l.push_back ( String( "abcd" ) );
l.push_back ( String( "acd" ) );
l.push_back ( String( "ab" ) );
l.push_back ( String( "abcd" ) );
l.push_back ( String( "ac" ) );
l.push_back ( String( "ab" ) );
l.push_back ( String( "abx" ) );
String p = "ab";
std::sort( l.begin(), l.end() );
List range = getNames( l, p );
std::copy( range.begin(), range.end(),
std:
stream_iterator< String >( std::cout, "\n" ) );
}
Best
Kai-Uwe Bux