Related
can somebody help me with this function: suppose that I need to remove all even numbers from a vector using reference: can I do that? Is the push_back correct or should I use something else?
void evenRemoe(vector<int>& arr) {
for(int i = 0; i < arr.size(); i++) {
if(arr[i] % 2 != 0) {
push_back(arr[i]);
}
}
}
Using push_back adds elements so that's not going to work.
You can use std::erase_if with a functor, like a lambda or other function acting as a unary predicate, to decide what elements that should be removed.
void evenRemoe(std::vector<int>& arr) {
std::erase_if(arr, [](int i) { return i % 2 == 0; });
}
Prior to C++20 you could implement the erase–remove idiom
#include <algorithm>
void evenRemoe(std::vector<int>& arr) {
arr.erase(std::remove_if(arr.begin(), arr.end(),
[](int i) { return i % 2 == 0; }),
arr.end());
}
push_back is a method of std::vector for appending an element to the end of the vector, not removing. What you need is one of the erase methods.
However, you should be careful while erasing elements of the vector you're iterating over. Care must be taken to avoid incrementing the index when you remove the element.
The better way to do this is to use std::remove_if algorithm instead of iterating the vector yourself.
void evenRemove(vector<int>& arr) {
auto it = std::remove_if(arr.begin(), arr.end(),
[](int n) { return (n % 2) == 0; });
arr.erase(it, arr.end());
}
Despite the name, std::remove_if doesn't actually remove any elements from the vector. Instead, it moves the elements that match the predicate (in our case - all even integers) to the end of the vector and returns an iterator pointing to the first of such elements. Therefore, to actually remove the elements you need to call erase with the iterators denoting the tail of the vector that contains the even integers.
No, push_back() is not the correct thing to use. That is meant for adding values, not removing them.
Also, your code is actually looking for odd values, not even values.
You can use std::vector::erase() to remove individual values, eg:
void evenRemoe(vector<int>& arr){
for(size_t i = 0; i < arr.size();){
if (arr[i] % 2 == 0){
arr.erase(arr.begin()+i);
}else{
++i;
}
}
}
Alternatively, consider using the Erase-Remove idiom via std::remove_if() and std::vector::erase(), eg:
#include <algorithm>
void evenRemoe(vector<int>& arr){
arr.erase(
std::remove_if(arr.begin(), arr.end(),
[](int value){ return (value % 2) == 0; }
),
arr.end()
);
}
Or, in C++20, via std::erase_if(), eg:
void evenRemoe(vector<int>& arr){
std::erase_if(arr,
[](int value){ return (value % 2) == 0; }
);
}
From C++20 onwards you can use std::erase_if() , Prior to c++20 erase-remove idiom used to be the solution of this problem.
v.erase(std::remove_if(v.begin(), v.end(), is_even), v.end());
Where is_even is a functor
Remove multiple element from vector using iterator.
Just take care that when we erase using iterator,it goes invalid.
int main(){
vector<int> vec={1,2,3,4,5,6,7,8,9};
for(auto it=vec.begin();it!=vec.end();){
if(*it%2==0)
vec.erase(it);
else
it++;
}
for(auto i:vec){
cout<<i<<" ";
}
return 0;
}
output:1 3 5 7 9
2nd method
int main(){
vector<int> vec={1,2,3,4,5,6,7,8,9};
vec.erase(remove_if(vec.begin(),vec.end(),[](int i){
return i%2==0;
}),vec.end());
for(auto i:vec)
cout<<i<<" ";
return 0;
}
I wrote this code in C++ as part of a uni task where I need to ensure that there are no duplicates within an array:
// Check for duplicate numbers in user inputted data
int i; // Need to declare i here so that it can be accessed by the 'inner' loop that starts on line 21
for(i = 0;i < 6; i++) { // Check each other number in the array
for(int j = i; j < 6; j++) { // Check the rest of the numbers
if(j != i) { // Makes sure don't check number against itself
if(userNumbers[i] == userNumbers[j]) {
b = true;
}
}
if(b == true) { // If there is a duplicate, change that particular number
cout << "Please re-enter number " << i + 1 << ". Duplicate numbers are not allowed:" << endl;
cin >> userNumbers[i];
}
} // Comparison loop
b = false; // Reset the boolean after each number entered has been checked
} // Main check loop
It works perfectly, but I'd like to know if there is a more elegant or efficient way to check.
You could sort the array in O(nlog(n)), then simply look until the next number. That is substantially faster than your O(n^2) existing algorithm. The code is also a lot cleaner. Your code also doesn't ensure no duplicates were inserted when they were re-entered. You need to prevent duplicates from existing in the first place.
std::sort(userNumbers.begin(), userNumbers.end());
for(int i = 0; i < userNumbers.size() - 1; i++) {
if (userNumbers[i] == userNumbers[i + 1]) {
userNumbers.erase(userNumbers.begin() + i);
i--;
}
}
I also second the reccomendation to use a std::set - no duplicates there.
The following solution is based on sorting the numbers and then removing the duplicates:
#include <algorithm>
int main()
{
int userNumbers[6];
// ...
int* end = userNumbers + 6;
std::sort(userNumbers, end);
bool containsDuplicates = (std::unique(userNumbers, end) != end);
}
Indeed, the fastest and as far I can see most elegant method is as advised above:
std::vector<int> tUserNumbers;
// ...
std::set<int> tSet(tUserNumbers.begin(), tUserNumbers.end());
std::vector<int>(tSet.begin(), tSet.end()).swap(tUserNumbers);
It is O(n log n). This however does not make it, if the ordering of the numbers in the input array needs to be kept... In this case I did:
std::set<int> tTmp;
std::vector<int>::iterator tNewEnd =
std::remove_if(tUserNumbers.begin(), tUserNumbers.end(),
[&tTmp] (int pNumber) -> bool {
return (!tTmp.insert(pNumber).second);
});
tUserNumbers.erase(tNewEnd, tUserNumbers.end());
which is still O(n log n) and keeps the original ordering of elements in tUserNumbers.
Cheers,
Paul
It is in extension to the answer by #Puppy, which is the current best answer.
PS : I tried to insert this post as comment in the current best answer by #Puppy but couldn't so as I don't have 50 points yet. Also a bit of experimental data is shared here for further help.
Both std::set and std::map are implemented in STL using Balanced Binary Search tree only. So both will lead to a complexity of O(nlogn) only in this case. While the better performance can be achieved if a hash table is used. std::unordered_map offers hash table based implementation for faster search. I experimented with all three implementations and found the results using std::unordered_map to be better than std::set and std::map. Results and code are shared below. Images are the snapshot of performance measured by LeetCode on the solutions.
bool hasDuplicate(vector<int>& nums) {
size_t count = nums.size();
if (!count)
return false;
std::unordered_map<int, int> tbl;
//std::set<int> tbl;
for (size_t i = 0; i < count; i++) {
if (tbl.find(nums[i]) != tbl.end())
return true;
tbl[nums[i]] = 1;
//tbl.insert(nums[i]);
}
return false;
}
unordered_map Performance (Run time was 52 ms here)
Set/Map Performance
You can add all elements in a set and check when adding if it is already present or not. That would be more elegant and efficient.
I'm not sure why this hasn't been suggested but here is a way in base 10 to find duplicates in O(n).. The problem I see with the already suggested O(n) solution is that it requires that the digits be sorted first.. This method is O(n) and does not require the set to be sorted. The cool thing is that checking if a specific digit has duplicates is O(1). I know this thread is probably dead but maybe it will help somebody! :)
/*
============================
Foo
============================
*
Takes in a read only unsigned int. A table is created to store counters
for each digit. If any digit's counter is flipped higher than 1, function
returns. For example, with 48778584:
0 1 2 3 4 5 6 7 8 9
[0] [0] [0] [0] [2] [1] [0] [2] [2] [0]
When we iterate over this array, we find that 4 is duplicated and immediately
return false.
*/
bool Foo(int number)
{
int temp = number;
int digitTable[10]={0};
while(temp > 0)
{
digitTable[temp % 10]++; // Last digit's respective index.
temp /= 10; // Move to next digit
}
for (int i=0; i < 10; i++)
{
if (digitTable [i] > 1)
{
return false;
}
}
return true;
}
It's ok, specially for small array lengths. I'd use more efficient aproaches (less than n^2/2 comparisons) if the array is mugh bigger - see DeadMG's answer.
Some small corrections for your code:
Instead of int j = i writeint j = i +1 and you can omit your if(j != i) test
You should't need to declare i variable outside the for statement.
I think #Michael Jaison G's solution is really brilliant, I modify his code a little to avoid sorting. (By using unordered_set, the algorithm may faster a little.)
template <class Iterator>
bool isDuplicated(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::unordered_set<T> values(begin, end);
std::size_t size = std::distance(begin,end);
return size != values.size();
}
//std::unique(_copy) requires a sorted container.
std::sort(cont.begin(), cont.end());
//testing if cont has duplicates
std::unique(cont.begin(), cont.end()) != cont.end();
//getting a new container with no duplicates
std::unique_copy(cont.begin(), cont.end(), std::back_inserter(cont2));
#include<iostream>
#include<algorithm>
int main(){
int arr[] = {3, 2, 3, 4, 1, 5, 5, 5};
int len = sizeof(arr) / sizeof(*arr); // Finding length of array
std::sort(arr, arr+len);
int unique_elements = std::unique(arr, arr+len) - arr;
if(unique_elements == len) std::cout << "Duplicate number is not present here\n";
else std::cout << "Duplicate number present in this array\n";
return 0;
}
As mentioned by #underscore_d, an elegant and efficient solution would be,
#include <algorithm>
#include <vector>
template <class Iterator>
bool has_duplicates(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::vector<T> values(begin, end);
std::sort(values.begin(), values.end());
return (std::adjacent_find(values.begin(), values.end()) != values.end());
}
int main() {
int user_ids[6];
// ...
std::cout << has_duplicates(user_ids, user_ids + 6) << std::endl;
}
fast O(N) time and space solution
return first when it hits duplicate
template <typename T>
bool containsDuplicate(vector<T>& items) {
return any_of(items.begin(), items.end(), [s = unordered_set<T>{}](const auto& item) mutable {
return !s.insert(item).second;
});
}
Not enough karma to post a comment. Hence a post.
vector <int> numArray = { 1,2,1,4,5 };
unordered_map<int, bool> hasDuplicate;
bool flag = false;
for (auto i : numArray)
{
if (hasDuplicate[i])
{
flag = true;
break;
}
else
hasDuplicate[i] = true;
}
(flag)?(cout << "Duplicate"):("No duplicate");
I have a std::vector<string> where each element is a word. I want to print the vector without repeated words!
I searched a lot on the web and I found lots of material, but I can't and I don't want to use hash maps, iterators and "advanced" (to me) stuff. I can only use plain string comparison == as I am still a beginner.
So, let my_vec a std::vector<std::string> initialized from std input. My idea was to read all the vector and erase any repeated word once I found it:
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
}
}
}
I tried to test for std::vector<std::string> my_vec{"hey","how","are","you","fine","and","you","fine"}
and indeed I found
hey how are you fine and
so it seems to be right, but for instance if I write the simple vector std::vector<std::string> my_vec{"hello","hello","hello","hello","hello"}
I obtain
hello hello
The problem is that at every call to erase the dimension gets smaller and so I lose information. How can I do that?
Minimalist approach to your existing code. The auto-increment of j is what is ultimately breaking your algorithm. Don't do that. Instead, only increment it when you do NOT remove an element.
I.e.
for (int i = 0; i < my_vec.size(); ++i) {
for (int j = i + 1; j < my_vec.size(); ) { // NOTE: no ++j
if (my_vec[i] == my_vec[j]) {
my_vec.erase(my_vec.begin() + j);
}
else ++j; // NOTE: moved to else-clause
}
}
That is literally it.
You can store the element element index to erase and then eliminate it at the end.
Or repeat the cycle until no erase are performed.
First code Example:
std::vector<int> index_to_erase();
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
index_to_erase.push_back(j);
}
}
}
//starting the cycle from the last element to the vector of index, in this
//way the vector of element remains equal for the first n elements
for (int i = index_to_erase.size()-1; i >= 0; i--){
my_vec.erase(my_vec.begin()+index_to_erase[i]); //remove the component from the vector
}
Second code Example:
bool Erase = true;
while(Erase){
Erase = false;
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
Erase = true;
}
}
}
}
Why don't you use std::unique?
You can use it as easy as:
std::vector<std::string> v{ "hello", "hello", "hello", "hello", "hello" };
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
N.B. Elements need to be sorted because std::unique works only for consecutive duplicates.
In case you don't want to change the content of the std::vector, but only have stable output, I recommend other answers.
Erasing elements from a container inside a loop is a little tricky, because after erasing element at index i the next element (in the next iteration) is not at index i+1 but at index i.
Read about the erase-remove-idiom for the idomatic way to erase elements. However, if you just want to print on the screen there is a much simpler way to fix your code:
for(int i=0; i<my_vec.size(); ++i){
bool unique = true;
for (int j=0; j<i; ++j){
if(my_vec[i]==my_vec[j]) {
unique = false;
break;
}
if (unique) std::cout << my_vec[i];
}
}
Instead of checking for elements after the current one you should compare to elements before. Otherwise "bar x bar y bar" will result in "x x bar" when I suppose it should be "bar x y".
Last but not least, consider that using the traditional loops with indices is the complicated way, while using iterators or a range-based loop is much simpler. Don't be afraid of new stuff, on the long run it will be easier to use.
You can simply use the combination of sort and unique as follows.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::string> vec{"hey","how","are","you","fine","and","you","fine"};
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end() ), vec.end());
for (int i = 0; i < vec.size(); i ++) {
std::cout << vec[i] << " ";
}
std::cout << "\n";
return 0;
}
I'm trying to remove the same integer numbers in a vector. My aim is to have only one copy them. Well I wrote a simple code, but it doesn't work properly. Can anyone help? Thanks in advance.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int a = 10, b = 10 , c = 8, d = 8, e = 10 , f = 6;
vector<int> vec;
vec.push_back(a);
vec.push_back(b);
vec.push_back(c);
vec.push_back(d);
vec.push_back(e);
vec.push_back(f);
for (int i=vec.size()-1; i>=0; i--)
{
for(int j=vec.size()-1; j>=0; j--)
{
if(vec[j] == vec[i-1])
vec.erase(vec.begin() + j);
}
}
for(int i=0; i<vec.size(); i++)
{
cout<< "vec: "<< vec[i]<<endl;
}
return 0;
}
Don't use a list for this. Use a set:
#include <set>
...
set<int> vec;
This will ensure you will have no duplicates by not adding an element if it already exists.
To remove duplicates it's easier if you sort the array first. The code below uses two different methods for removing the duplicates: one using the built-in C++ algorithms and the other using a loop.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main() {
int a = 10, b = 10 , c = 8, d = 8, e = 10 , f = 6;
vector<int> vec;
vec.push_back(a);
vec.push_back(b);
vec.push_back(c);
vec.push_back(d);
vec.push_back(e);
vec.push_back(f);
// Sort the vector
std::sort(vec.begin(), vec.end());
// Remove duplicates (v1)
std::vector<int> result;
std::unique_copy(vec.begin(), vec.end(), std::back_inserter(result));
// Print results
std::cout << "Result v1: ";
std::copy(result.begin(), result.end(), std::ostream_iterator<int>(cout, " "));
std::cout << std::endl;
// Remove duplicates (v2)
std::vector<int> result2;
for (int i = 0; i < vec.size(); i++) {
if (i > 0 && vec[i] == vec[i - 1])
continue;
result2.push_back(vec[i]);
}
// Print results (v2)
std::cout << "Result v2: ";
std::copy(result2.begin(), result2.end(), std::ostream_iterator<int>(cout, " "));
std::cout << std::endl;
return 0;
}
If you need to save initial order of numbers you can make a function that will remove duplicates using helper set<int> structure:
void removeDuplicates( vector<int>& v )
{
set<int> s;
vector<int> res;
for( int i = 0; i < v.size(); i++ ) {
int x = v[i];
if( s.find(x) == s.end() ) {
s.insert(x);
res.push_back(x);
}
}
swap(v, res);
}
The problem with your code is here:
for(int j=vec.size()-1; j>=0; j--)
{
if(vec[j] == vec[i-1])
vec.erase(vec.begin() + j);
}
there's going to be a time when j==i-1 and that's going to kill your algorithms and there will be a time when i-1 < 0 so you will get an out of boundary exception.
What you can do is to change your for loop conditions:
for (int i = vec.size() - 1; i>0; i--){
for(int j = i - 1; j >= 0; j--){
//do stuff
}
}
this way, your the two variables your comparing will never be the same and your indices will always be at least 0.
Others have already pointed to std::set. This is certainly simple and easy--but it can be fairly slow (quite a bit slower than std::vector, largely because (like a linked list) it consists of individually allocated nodes, linked together via pointers to form a balanced tree1.
You can (often) improve on that by using an std::unordered_set instead of a std::set. This uses a hash table2 instead of a tree to store the data, so it normally uses contiguous storage, and gives O(1) expected access time instead of the O(log N) expected for a tree.
An alternative that's often faster is to collect the data in the vector, then sort the data and use std::unique to eliminate duplicates. This tends to be best when you have two distinct phases of operation: first you collect all the data, then you need duplicates removed. If you frequently alternate between adding/deleting data, and needing a duplicate free set, then something like std::set or std::unordered_set that maintain the set without duplicates at all times may be more useful.
All of these also affect the order of the items. An std::set always maintains the items sorted in a defined order. With std::unique you need to explicit sort the data. With std::unordered_set you get the items sorted in an arbitrary order that's neither their original order nor is it sorted.
If you need to maintain the original order, but without duplicates, you normally end up needing to store the data twice. For example when you need to add a new item, you attempt to insert it into an std::unordered_set, then if and only if that succeeds, add it to the vector as well.
Technically, implementation as a tree isn't strictly required, but it's about the only possibility of which I'm aware that can meet the requirements, and all the implementations of which I'm aware are based on trees.
Again, other implementations might be theoretically possible, but all of which I'm aware use hashing--but in this case, enough of the implementation is exposed that avoiding a hash table would probably be even more difficult.
The body of a range for must not change the size of the sequence over which it is iterating..
you can remove duplicates before push_back
void push(std::vector<int> & arr, int n)
{
for(int i = 0; i != arr.size(); ++i)
{
if(arr[i] == n)
{
return;
}
}
arr.push_back(n);
}
... ...
push(vec, a);
push(vec, b);
push(vec, c);
...
I have a bunch of strings that I need to sort. I think a std::vector would be the easiest way to do this. However, I've never used vectors before and so would like some help.
I just need to sort them alphanumerically, nothing special. Indeed, the string::compare function would work.
After that, how can I iterate through them to verify that they're sorted?
Here's what I have so far:
std::sort(data.begin(), data.end(), std::string::compare);
for(std::vector<std::string>::iterator i = data.begin(); i != data.end(); ++i)
{
printf("%s\n", i.c_str);
}
You can just do
std::sort(data.begin(), data.end());
And it will sort your strings. Then go through them checking whether they are in order
if(names.empty())
return true; // empty vector sorted correctly
for(std::vector<std::string>::iterator i=names.begin(), j=i+1;
j != names.end();
++i, ++j)
if(*i > *j)
return false;
return true; // sort verified
In particular, std::string::compare couldn't be used as a comparator, because it doesn't do what sort wants it to do: Return true if the first argument is less than the second, and return false otherwise. If you use sort like above, it will just use operator<, which will do exactly that (i.e std::string makes it return first.compare(second) < 0).
What is the question exactly? It seems everything is already there.
However, you should probably use std::cout << *i << std::endl;
i is an iterator == pointer to the data in the container, so * is needed
c_str() is a function of std::string and not a variable
The problems in your code do not relate to your question?
Some hints for you:
std::vector also overrides [] operator, so you can instead save the iterator hassle and use it like an array (iterate from 0 to vector.size()).
You could use std::set instead, which has automatically sorting on insertion (binary tree), so you save the extra sorting.
Using a functor makes your output even more fun: copy(V.begin(), V.end(), ostream_iterator<std::string>(cout, "\n"));
litb is correct, as always.
I just wanted to point out the more general point - anything that can be compared with < can be sorted with std::sort. I'll sometimes sneak an operator< member function into a struct, just so I can do this.
For sort use:
std::sort or std::vector< std::string>::sort(..) method.
To check if it is sorted:
use std::is_sorted for check is sorted - http://www.sgi.com/tech/stl/is_sorted.html
or
std::adjacent_find( v.begin(), v.end(), std::greater< std::string >() ) == v.end()
for your case you could use default comparator
EDITED:
std::is_sorted is not standard stl function, it defined in sgi stl implementation.
Thanks #Brian Neal for this note.
Sorting the string:
using namespace std; // to avoid using std everywhere
std::sort(data.begin(), data.end()); // this will sort the strings
Checking whether vector is sorted:
if(vec.empty())
return true; // empty vector is sorted correctly
for(std::vector< std::string>::iterator i=vec.begin(), j=i+1; j != vec.end(); ++i, ++j)
if(*i > *j) return false;
return true; // sort verified
C++11 Method to check sorted vector:
std::is_sorted(vec.begin(),vec.end())
Now printing the sorted vector:
for(std::vector< std::string>::iterator i = vec.begin(); i != vec.end(); ++i)
{
std::cout<< *i <<std::endl;
}
You could use a std::set, which is naturally a sorted container.
Try using comaprator:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//comparing function only sorts if string size is equal and keeps the larger integgers at last.
bool myfunction (string i,string j)
{
int n=i.length();
int m=j.length();
if(n==m)
return (i<j);
return n<m;
}
int main() {
int n;
cin>>n;
vector <string> arr(n);
for(int i=0;i<n;i++)
cin>>arr[i];
sort(arr.begin(),arr.end(),myfunction);
for(int i=0;i<n;i++)
cout<<arr[i]<<endl;
return 0;
}