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;
}
}
Related
Just like in topic. I would like to copy one vector to another without first row and column.
'''
std::vector<std::vector<int>> v2(v1.size()-1,std::vector<int>(v1.size()-1));
std::copy((v1.begin()+1)->begin()+1,v1.end()->end(),v2.begin()->begin());
return v2;
'''
Using C++ and views it is easy to drop items while enumerating.
So you can avoid using raw or iterator loops.
Live demo here : https://godbolt.org/z/8xz91Y8cK
#include <ranges>
#include <iostream>
#include <vector>
auto reduce_copy(const std::vector<std::vector<int>> values)
{
std::vector<std::vector<int>> retval{};
// drop first row
for (const auto& row : values | std::views::drop(1))
{
// add a new row to retval
auto& new_row = retval.emplace_back();
// drop first column
for (const auto& col : row | std::views::drop(1))
{
new_row.emplace_back(col);
}
}
return retval;
}
int main()
{
std::vector<std::vector<int>> values{ {1,2,3}, {4,5,6}, {7,8,9} };
auto result = reduce_copy(values);
for (const auto& row : result)
{
for (const auto& value : row)
{
std::cout << value << " ";
}
std::cout << "\n";
}
return 0;
}
You can use for example the ordinary for loop
#include <vector>
#include <iterator>
#include <algorithm>
//...
for ( auto first = std::next( std::begin( v1 ) ), target = std::begin( v2 );
first != std::end( v1 );
++first, ++target )
{
std::copy( std::next( std::begin( *first ) ), std::end( *first ), std::begin( *target ) );
}
How can I delete duplicates from two vectors of strings (delete them from both vectors) using only iterators?
I suppose it doesn't work because if values are already deleted they can't be compared, but I can not think of any other solution, only if I had one function to erase both elements at the same time.
void obrisiIsteRijeci(std::vector<std::string>& v1, std::vector<std::string>& v2){
for(auto it = v1.begin(); it != v1.end(); it++){
auto it1 = it;
for(auto it2 = v2.begin(); it2 != v2.end(); it2++){
if((*(it2) == *(it1)) && (*(it1) == *(it2))){
v1.erase(it1);
v2.erase(it2);
}
}
}
}
I can suggest the following approach. In the demonstration program below I am using vectors of the type std::vector<int> for simplicity.
#include <iostream>
#include <vector>
#include <iterator>
$include <algorithm>
int main()
{
std::vector<int> v1 = { 1, 2, 1, 2, 3, 4 }, v2 = { 1, 2, 3, 5 };
for (auto first = std::begin( v1 ); first != std::end( v1 ); )
{
auto it = std::find( std::begin( v2 ), std::end( v2 ), *first );
if (it != std::end( v2 ))
{
v2.erase( std::remove( it, std::end( v2 ), *first ), std::end( v2 ) );
auto value = *first;
auto offset = std::distance( std::begin( v1 ), first );
v1.erase( std::remove( first, std::end( v1 ), value ), std::end( v1 ) );
first = std::next( std::begin( v1 ), offset );
}
else
{
++first;
}
}
for (const auto &item : v1)
{
std::cout << item << ' ';
}
std::cout << '\n';
for (const auto &item : v2)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
The program output is
4
5
How can I delete duplicate elements from a vector but starting from the front?
So
2 3 4 5 2 5 would become 3 4 2 5
1 5 3 1 would become 5 3 1
I would like the solution to be easy to read, and it would be nice if it had good performance as well.
If a container supports bidirectional iterators then it is unimportant from which side of the container you are trying to remove duplicate elements because you can use reverse iterators.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename ForwardIterator>
ForwardIterator remove_duplicates( ForwardIterator first, ForwardIterator last )
{
for ( ; first != last; ++first )
{
last = std::remove( std::next( first ), last, *first );
}
return last;
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
v.erase( remove_duplicates( std::begin( v ), std::end( v ) ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
std::cout << '\n';
v.assign( { 1, 2, 3, 4, 5, 4, 3, 2, 1 } );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
v.erase( std::begin( v ), remove_duplicates( std::rbegin( v ), std::rend( v ) ).base() );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
The program output is
1 2 3 4 5 4 3 2 1
1 2 3 4 5
1 2 3 4 5 4 3 2 1
5 4 3 2 1
An asymptotically efficient algorithm (N log N):
Create a range of iterators each pointing to the original container
Sort the iterators with a stable sort. Use a comparison function that indirects through the iterator.
Remove consecutive duplicates (std::unique) using reverse iterator and similar custom comparison function.
std::remove_if from the vector with a predicate function that removes elements whose iterator isn't in the secondary container.
It's a bit more complex than the O(N*N) solution. Here is an example implementation. I cannot guarantee that it is correct:
template<class It, class Sentinel>
auto remove_duplicates(It first, Sentinel last)
{
std::vector<It> iterators;
auto iterator_generator = [it = first]() mutable {
return it++;
};
std::generate_n(
std::back_inserter(iterators),
last - first,
iterator_generator);
auto iterator_compare = [](const auto& l, const auto& r) {
return *l < *r;
};
std::stable_sort(
iterators.begin(),
iterators.end(),
iterator_compare);
auto iterator_eq = [](const auto& l, const auto& r) {
return *l == *r;
};
auto last_unique = std::unique(
iterators.begin(),
iterators.end(),
iterator_eq);
iterators.erase(last_unique, iterators.end());
auto keep_generator = [it = first]() mutable {
return it++;
};
std::vector<bool> remove(last - first, true);
for(auto it : iterators) {
auto index = it - first;
remove[index] = false;
}
auto remove_predicate = [index = 0, remove = std::move(remove)](const auto& el) mutable {
return remove[index++];
};
return std::remove_if(first, last, std::move(remove_predicate));
}
// usage with reverse iterators
v.erase(
v.rend().base(),
remove_duplicates(v.rbegin(), v.rend()).base());
I want to sort an array containing pair <int, pair <int, int> >, by the first value, in descending order.
I had
pair <int, pair<int, int> > adj[10];
which had values in it, unsorted.
When I used
sort(adj, adj + 10);
it would sort the array based on the adj[i].first value, in ascending order.
However, when I tried sorting in descending order
sort(adj, adj + 10, greater<int>());
It wasn't letting me.
Is there other way to sort by descending order?
You could write:
std::sort(std::begin(adj), std::end(adj),
std::greater<std::pair<int, std::pair<int, int>>>{});
In c++14, you could simplify this to:
std::sort(std::begin(adj), std::end(adj), std::greater<>{});
In c++17, you could simply it a little more:
std::sort(std::begin(adj), std::end(adj), std::greater{});
In c++20, you could simplify this much further:
std::ranges::sort(adj, std::greater{});
You can write a custom predicate using a lambda.
std::sort(std::begin(adj),
std::end(adj),
[](auto const& lhs, auto const& rhs)
{
return lhs.first > rhs.first;
});
Note that the above predicate only considers the first element. You could expand that to look at the further elements if you wanted more complex sorting.
A simple way is to use a lambda expression as for example
#include <utility>
#include <iterator>
#include <algorithm>
//...
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 1, 2 } } { 1, { 2, 1 } }
As you can see from the output if two elements of the array have equal values of the first member of an object of the type std::pair then values of the second member are not taken into account and can be unordered.
Another approach is to use the expression std::gretar<>(). That is to use the default template argument for the functional object std::greater. Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ), std::greater<>() );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 2, 1 } } { 1, { 1, 2 } }
In this case if two elements have an equal value of the first member then they are ordered according to values of the second member.
If your compiler does not support the C++ 14 Standard then the same effect of using std::greater<> you can achieve using the following lambda expression.
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b < a;
} );
since you are using c++14 here is how: sort using std::greater<>{}
std::pair <int, std::pair<int, int> > adj[3];
adj[0]=std::make_pair(10,std::make_pair(0,0));
adj[1]=std::make_pair(1,std::make_pair(0,0));
adj[2]=std::make_pair(7,std::make_pair(0,0));
std::sort(adj, adj+3, std::greater<>{});
std::cout << "Sorted \n";
for (auto x=0; x<3;++x)
std::cout << "x: " << adj[x].first << "\n";
return 0;
I was writing the insert function for std::vector for my personal project.
Vector layout before insert:
position : 0 1 2 3 4
Value : a b c e f
Assuming there is enough capacity, I want to insert 'd' at position 3.
Vector layout after insert:
position : 0 1 2 3 4 5
Value : a b c d e f
I wrote a function to shift the values to the right after the given insert position (in the example it is 3) and then I assign the given value at the requested insert position.
The function I wrote to shift_right is as follows:
template <typename T>
void vector<T>::shift_right(typename vector<T>::iterator given_pos) {
for (auto iter = end() - 1; iter != given_pos - 1; iter--) {
*(iter + 1) = *iter;
}
}
Is there a std::algorithm, or variation of it that can help me get rid of my raw loop in the shift_right function?
You can use std::move_backward:
template< class BidirIt1, class BidirIt2 ><br>
BidirIt2 move_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last );
Moves the elements from the range [first, last), to another range ending at d_last. The elements are moved in reverse order (the last element is moved first), but their relative order is preserved.
So your code might look like this (not tested):
template <typename T>
void vector<T>::shift_right(typename vector<T>::iterator given_pos) {
std::move_backward(given_pos, end()-2, end()-1);
}
This assumes that the capacity has already been increased if necessary and that end() returns the new end iterator (i.e. one past the last element after the new space was inserted). Change to std::move_backward(given_pos, end()-1, end()); if that's not the case.
It seems you mean something like the following
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename T>
typename std::vector<T>::iterator
shift_right( std::vector<T> &v, typename std::vector<T>::size_type pos )
{
v.resize( v.size() + 1 );
typename std::vector<T>::iterator result = std::end( v );
if ( pos < v.size() )
{
result = std::copy_backward( std::next( std::begin( v ), pos ),
std::prev( std::end( v )),
std::end( v ) );
}
return std::prev( result );
}
int main()
{
std::vector<int> v;
auto it = shift_right( v, v.size( ) );
*it = 2;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
it = shift_right( v, v.size() );
*it = 3;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
it = shift_right( v, 0 );
*it = 0;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
it = shift_right( v, 1 );
*it = 1;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
return 0;
}
The program output is
2
2 3
0 2 3
0 1 2 3
Pay attention to that it is better to use std::copy_backward instead of std::move_backward because in the first case the state of all elements of the vector will be consistent similarly to elements of an array of fundamental types after shifting them.
If to use std::move_backward then the corresponding function can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename T>
typename std::vector<T>::iterator
shift_right( std::vector<T> &v, typename std::vector<T>::size_type pos )
{
v.resize( v.size() + 1 );
typename std::vector<T>::iterator result = std::end( v );
if ( pos < v.size() )
{
result = std::move_backward( std::next( std::begin( v ), pos ),
std::prev( std::end( v )),
std::end( v ) );
}
result = std::prev( result );
*result = T();
return result;
}
int main()
{
std::vector<int> v = { 1, 2, 4, 5, 6 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
auto it = shift_right( v, 2 );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
*it = 3;
for ( const auto &item : v ) std::cout << item << ' ';
std::cout <<'\n';
return 0;
}
The program output is
1 2 4 5 6
1 2 0 4 5 6
1 2 3 4 5 6
I would first define a convenience function template, right_shift_by_one(), that shifts the elements to the right by one position in the valid iterator range [first, last):
template<typename BidirIt>
void right_shift_by_one(BidirIt first, BidirIt last) {
std::move_backward(first, std::prev(last), last);
}
Then, your custom vector's member function, shift_right(), which eventually calls the convenience function defined above:
template<typename T>
auto shift_right(typename vector<T>::iterator pos) {
auto dist = std::distance(begin(), pos);
// this only compiles if T is default constructible
resize(size()+1);
// resize() may have invalidated the pos iterator due to vector's reallocation
// recompute it
pos = begin() + dist;
right_shift_by_one(pos, end());
return pos;
}
This member function returns an iterator pointing to the element corresponding to the new space created by right shifting. This works even if the vector doesn't have enough capacity because the invalidation of iterators on reallocation has been taken into account. You have to implement resize() in your custom vector implementation, though.
Use:
auto it = shift_right(vec.begin() + 2);
*it = 'c';