I am trying to compare two vectors which are of size of multiple of 4 and data is represented in terms of blocks (4 elements). Each vector block has a unique number it e.g {0,0,0,0}, {0,0,0,1}, {0,0,0,2} or {0,0,0,0,0,0,0,1,0,0,0,2} and {0,0,0,2,0,0,0,1} so on. I am using iterator which increments i+=4 every time. I wrote a small function which do the job but the blocks tend to repeat. I am not sure how t0 remove repetition of these block. e.g vector_A {0,0,0,0,0,0,0,1} vector_B {0,0,0,1,0,0,0,0,0,0,0,2} it should give local_vector1 {0,0,0,2} instead I get local vector_1 {0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,2}
void comparing_vectors_by_block(std::vector<int> vector_A, std::vector<int>
vector_B)
{
const int blockSize = 4;
std::vector<int> local_vector1;
std::cout << "size of the vector_A: " << vector_A.size() << std::endl;
std::cout << "size of the vector_B: " << vector_B.size() << std::endl;
for (auto it_A = std::begin(vector_A); it_A != std::end(vector_A); it_A+=4)
{
for (auto it_B = std::begin(vector_B); it_B != std::end(vector_B); it_B += 4)
{
bool match = equal(it_A, it_A + blockSize, it_B, it_B + blockSize);
if (!match)
{
std::cout << "match :" << std::endl;
local_vector1.insert(local_vector1.end(), it_B, it_B + blockSize);
}
else
{
std::cout << "not matched :" << std::endl;
}
}
}
Use a vector of arrays of four ints to represent the data.
std::vector<std::array<int,4>> vect1;
If this data has some other meaning. It is better to use the OOP way and create
a struct or a class to represent that four numbers data. Then implement operator == and other helpful methods for the struct/class.
struct foo{
int a;
int b;
int c;
ind d;
};
bool foo::operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
Then just iterate the vector and compare the elements using == like you would do if the vector was of type int for example.
for(auto& x : vector_A)
{
if(std::find(vector_B.begin(), vector_B.end(), x) != vector_B.end()) {
local_vector1.append(x);
}
}
If I got you right, you want to get the symmetric difference of two vectors of blocks. I.e. for A = {0,0,0,3,0,0,0,0,0,0,0,1} and B = {0,0,0,1,0,0,0,0,0,0,0,2} you want to have local_vector1 = {0,0,0,3,0,0,0,2}.
In your implementation you compare each block of vector A with each block of vector B -- of course, you'll get extra mismatches. My (also non-optimized) solution:
std::vector<int> get_blocked_vectors_diff( const std::vector<int>& vector_A, const std::vector<int>& vector_B )
{
const int blockSize = 4;
std::vector<int> local_vector;
for ( auto it_A = std::begin( vector_A ); it_A != std::end( vector_A ); it_A += 4 )
{
bool found_in_B = false;
for ( auto it_B = std::begin( vector_B ); !found_in_B && it_B != std::end( vector_B ); it_B += 4 )
{
found_in_B = std::equal( it_A, it_A + blockSize, it_B, it_B + blockSize );
}
if ( !found_in_B )
{
local_vector.insert( local_vector.end( ), it_A, it_A + blockSize );
}
}
return local_vector;
}
void comparing_vectors_by_block(std::vector<int> vector_A, std::vector<int> vector_B)
{
auto A_mines_B = get_blocked_vectors_diff( vector_A, vector_B );
auto B_mines_A = get_blocked_vectors_diff( vector_B, vector_A );
auto local_vector1( A_mines_B );
local_vector1.insert( local_vector1.end(), B_mines_A.begin( ), B_mines_A.end( ) );
for ( auto a : local_vector1 )
{
std::cout << a << " ";
}
std::cout << std::endl;
}
Note, that we need two parts of the answer: A\B and B\A, so get_blocked_vectors_diff is called twice.
If you change your data structure like Petar Velev suggested, you will be able to shorten get_blocked_vectors_diff function:
std::vector<int> get_blocked_vectors_diff( const std::vector<Block>& vector_A, const std::vector<Block>& vector_B )
{
std::vector<Block> local_vector;
for ( auto& x : vector_A )
{
if ( std::find( vector_B.begin( ), vector_B.end( ), x ) == vector_B.end( ) )
{
local_vector.push_back( x );
}
}
return local_vector;
}
Better solutions could be obtained if you sort your vectors of blocks first.
Related
I need help getting the first layer index of a 2D vector. Each element is unique, so there are no repetitions of element. Here's what I mean bellow.
I have a vector defined as:
vector<vector<int>> vec { {0,1} ,
{2} ,
{3,4},
{5,6} }
Then, I want to get the index of where any of the numbers is, on the "first" layer.
By this, I mean if I say
index of 4, it should return 2.
If I say, index of 6, it should return 3.
Thank you in advance!
You can use std::find and std::find_if:
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<std::vector<int>> vec { {0,1} ,
{2} ,
{3,4},
{5,6} };
// Search for the 4
auto iter = std::find_if(vec.begin(), vec.end(), [](const std::vector<int>& v)
{return std::find(v.begin(), v.end(), 4) != v.end();});
// Output the distance between the item and the beginning of the vector
std::cout << std::distance(vec.begin(), iter);
}
Output:
2
The outer std::find_if searches the std::vector<vector<int>> and the argument to the lambda will be a reference to each inner vector. The inner std::find searches that inner vector for the value.
You could write a function that calculates the index like:
int findIndex(const std::vector<std::vector<int>> &vec, int val)
{
auto it = std::find_if(vec.cbegin(), vec.cend(), [val](const std::vector<int> &v) {
return std::find(v.cbegin(), v.cend(), val) != v.cend();
});
return it != vec.cend() ? std::distance(vec.cbegin(), it) : -1;
}
You can use the standard algorithm std::find_if along with the algorithm std::find.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<std::vector<int>> v =
{
{ 0, 1 }, { 2 }, { 3, 4 }, { 5, 6 }
};
auto present = []( const auto &v, const auto &value )
{
return std::find( std::begin( v ), std::end( v ), value ) != std::end( v );
};
int value = 4;
size_t i = std::distance( std::begin( v ),
std::find_if( std::begin( v ), std::end( v ),
[&, present, value]( const auto &item )
{
return present( item, value );
} ) );
if ( i != v.size() ) std::cout << value << ": " << i << '\n';
value = 6;
i = std::distance( std::begin( v ),
std::find_if( std::begin( v ), std::end( v ),
[&, present, value]( const auto &item )
{
return present( item, value );
} ) );
if ( i != v.size() ) std::cout << value << ": " << i << '\n';
return 0;
}
The program output is
4: 2
6: 3
You can use a hash-table data structure like unordered_map to do this in O(1) time.
unordered_map <int,int> m;
for(int i=0;i<vec.size();i++){
for(int j=0;j<vec[i].size();j++){
m[vec[i][j]] = i;
}
}
I got a class Matrix with a member std::list<Element> listMatrix;. Element is a a class with 3 int members line, column, value. I save in the list, elements of a matrix that are not 0 by saving the line, column and the value of the respectively element. I want to overload the operator [][] so I can do something like Matrix a; a[2][3] = 5;. I know you can't overload [][] directly.
Do overload Element& operator()(int, int) (and the const variant) so you can write
matrix(2, 3) = 5;
If you absolutely need the [2][3] syntax, you'd need to define a proxy class so matrix[2] return a proxy value and proxy[3] return the desired reference. But it comes with a lot of problems. The basic idea would be:
class naive_matrix_2x2
{
int data[4];
struct proxy
{
naive_matrix_2x2& matrix;
int x;
int& operator[](int y) { return matrix.data[x*2+y]; }
};
public:
proxy operator[](int x) { return {*this, x}; }
};
Full demo: https://coliru.stacked-crooked.com/a/fd053610e56692f6
The list is not a suitable container for using the subscript operator because it has no direct access to its elements without moving an iterator through the list.
So the operator will be inefficient.
It is better to use the standard container std::vector that already has the subscript operator.
Nevertheless answering your question the operator can be defined the following way. You can add to the operators an exception then an index will point outside the list.
#include <iostream>
#include <list>
struct A
{
int x, y, z;
int & operator []( size_t n )
{
return n == 0 ? x : n == 1 ? y : z;
}
const int & operator []( size_t n ) const
{
return n == 0 ? x : n == 1 ? y : z;
}
};
struct B
{
std::list<A> lst;
A & operator []( size_t n )
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
const A & operator []( size_t n ) const
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
};
int main()
{
B b = { { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } } };
std::cout << b[0][0] << '\n';
std::cout << b[0][1] << '\n';
std::cout << b[0][2] << '\n';
b[2][1] += 20;
std::cout << b[2][1] << '\n';
}
The program output is
1
2
3
28
I need to double-loop through the characters of each string in a vector array and am getting stuck on how what the syntax would be to call each character of each element.
the vector [] operator will return std::string&, then you use [] operator of std::string to get the character (as char&).
std::vector<std::string> vec{"hello","world"};
std::cout<<vec[0][3];
as #RyanP commented, the method std::vector::at and std::string::at will preform boundry check and will throw an exception if you try to dereference an index which is bigger than the vector/string size.
try{
std::cout<<vec.at(0).at(3);
}
catch (std::exception& e){
//handle
}
As you need to iterate over string in a vector, ie use it multiple times, create a (const) reference:
std::vector<std::string> vec { "abc", "efg" };
for( size_t i = 0; i < vec.size(); ++i ) {
const auto &str = vec[i];
for( size_t j = 0; j < str.length(); ++j )
std::cout << str[j];
}
Otherwise you would have to write vec[i][j] multiple times, which is too verbose
Here are shown different approaches
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> v = { "Hello", "World" };
for ( const auto &s : v )
{
for ( auto c : s ) std::cout << c;
std::cout << ' ';
}
std::cout << std::endl;
for ( auto i = v.size(); i != 0; )
{
for ( auto j = v[--i].size(); j != 0; ) std::cout << v[i][--j];
std::cout << ' ';
}
std::cout << std::endl;
for ( auto it1 = v.begin(); it1 != v.end(); ++it1 )
{
for ( auto it2 = it1->rbegin(); it2 != it1->rend(); ++it2 ) std::cout << *it2;
std::cout << ' ';
}
std::cout << std::endl;
}
The program output is
Hello World
dlroW olleH
olleH dlroW
You can combine these approaches in various ways.
If you want to change a character in a string using the range-based for statement then you have to write the loops the following way
for ( auto &s : v )
{
for ( auto &c : s ) /* assign something to c */;
}
I have the following piece of code. The code creates a vector Dataset, each element of which is a vector. It also creates a vector S.
I want to check which vector of Dataset contain vector of S. Apparently I am doing something wrong, because for the following example,
Dataset is:
a b c
a d
a b d
and S:
a b
it should print: 0 2
and for me it prints: 0 1 2
#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
class StringRef
{
private:
char const* begin_;
int size_;
public:
int size() const { return size_; }
char const* begin() const { return begin_; }
char const* end() const { return begin_ + size_; }
StringRef( char const* const begin, int const size )
: begin_( begin )
, size_( size )
{}
bool operator<(const StringRef& obj) const
{
return (strcmp(begin(),obj.begin()) > 0 );
}
};
/************************************************
* Checks if vector B is subset of vector A *
************************************************/
bool isSubset(std::vector<StringRef> A, std::vector<StringRef> B)
{
std::sort(A.begin(), A.end());
std::sort(B.begin(), B.end());
return std::includes(A.begin(), A.end(), B.begin(), B.end());
}
vector<StringRef> split3( string const& str, char delimiter = ' ' )
{
vector<StringRef> result;
enum State { inSpace, inToken };
State state = inSpace;
char const* pTokenBegin = 0; // Init to satisfy compiler.
for(auto it = str.begin(); it != str.end(); ++it )
{
State const newState = (*it == delimiter? inSpace : inToken);
if( newState != state )
{
switch( newState )
{
case inSpace:
result.push_back( StringRef( pTokenBegin, &*it - pTokenBegin ) );
break;
case inToken:
pTokenBegin = &*it;
}
}
state = newState;
}
if( state == inToken )
{
result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );
}
return result;
}
int main() {
vector<vector<StringRef> > Dataset;
vector<vector<StringRef> > S;
ifstream input("test.dat");
long count = 0;
int sec, lps;
time_t start = time(NULL);
cin.sync_with_stdio(false); //disable synchronous IO
for( string line; getline( input, line ); )
{
Dataset.push_back(split3( line ));
count++;
};
input.close();
input.clear();
input.open("subs.dat");
for( string line; getline( input, line ); )
{
S.push_back(split3( line ));
};
for ( std::vector<std::vector<StringRef> >::size_type i = 0; i < S.size(); i++ )
{
for(std::vector<std::vector<StringRef> >::size_type j=0; j<Dataset.size();j++)
{
if (isSubset(Dataset[j], S[i]))
{
cout << j << " ";
}
}
}
sec = (int) time(NULL) - start;
cerr << "C++ : Saw " << count << " lines in " << sec << " seconds." ;
if (sec > 0) {
lps = count / sec;
cerr << " Crunch speed: " << lps << endl;
} else
cerr << endl;
return 0;
}
Your StringRef type is dangerous because it contains a const char * pointer, but no concept of ownership. So the pointer could be invalidated at some point after the object is constructed.
And indeed this is what happens here: You have a single string (line) and create StringRefs with pointers to its internal data. When the string is later modified, these pointers are invalidated.
You should create a vector<std::string> instead to prevent this problem.
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).