Removing non-prime numbers from a vector - c++

I have a simple function that "primes a list" i.e. it returns the passed vector but without all non-primes. Essentially it removes non-primes from the vector and returns the updated vector. But my function just returns the vector without the numbers 0 and 1. Assume the vector is sorted in ascending order(0, 1, 2, 3, ... ) The basic structure of my function follows:
#include<vector>
#include<algorithms>
#include "cmath.h"
.
.
.
std::vector<int> prime_list(std::vector<int> foo){
int limit_counter = 1;
const int p_limit = sqrt(foo.at(foo.size() - 1));
for(int w = 0; w < foo.size(); w++){
if(foo.at(w) <= 1)
foo.erase(foo.begin() + w);
}
for(int i : foo){
do{
if(i % limit_counter == 0)
foo.erase(std::remove(foo.begin(), foo.end(), i), foo.end());
limit_counter++;
}
while(limit_counter < p_limit);
}
return foo;
}

const int p_limit = sqrt(foo.at(foo.size() - 1));
This will initialize the limit once, based on the last element in the list. You have to do that for each element being test for prime.
More importantly, limit_counter should be initialized for each i
Ignoring the problem with iterators, you can fix it with this pseudo code.
std::vector<int> prime_list(std::vector<int> foo)
{
foo.erase(std::remove(foo.begin(), foo.end(), 0), foo.end());
foo.erase(std::remove(foo.begin(), foo.end(), 1), foo.end());
for (int i : foo)
{
int limit_counter = 1;
const int p_limit = static_cast<int>(sqrt(i));
do
{
if (i % limit_counter == 0)
{
//undefined behavior, this might destroy the iterator for `i`
foo.erase(std::remove(foo.begin(), foo.end(), i), foo.end());
}
limit_counter++;
} while (limit_counter < p_limit);
}
return foo;
}
For an easier and safer solution, just create a new list and add the primes to it. Or, create a duplicate list primes and go through the loop in foo
std::vector<int> prime_list(std::vector<int> &foo)
{
std::vector<int> primes = foo;
primes.erase(std::remove(primes.begin(), primes.end(), 0), primes.end());
primes.erase(std::remove(primes.begin(), primes.end(), 1), primes.end());
for (int n : foo)
for (int k = 2, limit = static_cast<int>(sqrt(n)); k <= limit; k++)
if (n % k == 0)
primes.erase(std::remove(primes.begin(), primes.end(), n), primes.end());
return primes;
}

There are basically 2 possible solutions.
You can either erase none prime values from the std::vector
or copy just prime values to a new std::vector
For both solutions it is necessary to have a function, which detects, if a number is a prime or not. There are tons of such functions in the internet. Please select the best for your requirements.
Then, you need to think, if the erase/remove_if or the copy_if solution is better for you.
With erase/remove_if you are shifting a lot of memory, so, if you use it, then maybe better to start from the end.
On the other hand, copy_if may also invoke memory reallocation and copying, because of push_back and back_inserter actions.
So, sorry to say, it depends . . .
Please see below an example with both solutions.
#include <iostream>
#include <vector>
#include <algorithm>
// Some of the many isPrime functions, available in the internet
// Basically, for this example, it does not matter which
bool isPrime(int number){
if(number < 2) return false;
if(number % 2 == 0) return false;
for(int i=3; (i*i)<=number; i+=2)
if(number % i == 0 ) return false;
return true;
}
// Version with erase/remove idiom
// Yes, no reference for input parameter. Data shall be copied
auto primeVector1(std::vector<int> data) {
// Remove all none primes
data.erase(std::remove_if(data.begin(), data.end(), [](const int i){ return not isPrime(i);}),data.end());
return data;
}
// Version with copying prime data to new vector
auto primeVector2(std::vector<int>& data) {
std::vector<int> result{};
// Copy primes to new vector
std::copy_if(data.begin(), data.end(), std::back_inserter(result), [](const int i){ return isPrime(i);});
return result;
}
// Test/Driver code
int main() {
std::vector test{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
for (const int i : primeVector1(test)) std::cout << i << ' '; std::cout << '\n';
for (const int i : primeVector2(test)) std::cout << i << ' '; std::cout << '\n';
}

Related

Deleting both an element and its duplicates in a Vector in C++

I've searched the Internet and known how to delete an element (with std::erase) and finding duplicates of an element to then delete it (vec.erase(std::unique(vec.begin(), vec.end()),vec.end());). But all methods only delete either an element or its duplicates.
I want to delete both.
For example, using this vector:
std::vector<int> vec = {2,3,1,5,2,2,5,1};
I want output to be:
{3}
My initial idea was:
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
int passedNumber = 0; //To tell amount of number not deleted (since not duplicated)
for (int i = 0; i != vec.size(); i = passedNumber) //This is not best practice, but I tried
{
if (vec[i] == vec[i+1])
{
int ctr = 1;
for(int j = i+1; j != vec.size(); j++)
{
if (vec[j] == vec[i]) ctr++;
else break;
}
vec.erase(vec.begin()+i, vec.begin()+i+ctr);
}
else passedNumber++;
}
}
And it worked. But this code is redundant and runs at O(n^2), so I'm trying to find other ways to solve the problem (maybe an STL function that I've never heard of, or just improve the code).
Something like this, perhaps:
void removeDuplicatesandElement(std::vector<int> &vec) {
if (vec.size() <= 1) return;
std::sort(vec.begin(), vec.end());
int cur_val = vec.front() - 1;
auto pred = [&](const int& val) {
if (val == cur_val) return true;
cur_val = val;
// Look ahead to the next element to see if it's a duplicate.
return &val != &vec.back() && (&val)[1] == val;
};
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
Demo
This relies heavily on the fact that std::vector is guaranteed to have contiguous storage. It won't work with any other container.
You can do it using STL maps as follows:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void retainUniqueElements(vector<int> &A){
unordered_map<int, int> Cnt;
for(auto element:A) Cnt[element]++;
A.clear(); //removes all the elements of A
for(auto i:Cnt){
if(i.second == 1){ // that if the element occurs once
A.push_back(i.first); //then add it in our vector
}
}
}
int main() {
vector<int> vec = {2,3,1,5,2,2,5,1};
retainUniqueElements(vec);
for(auto i:vec){
cout << i << " ";
}
cout << "\n";
return 0;
}
Output:
3
Time Complexity of the above approach: O(n)
Space Complexity of the above approach: O(n)
From what you have searched, we can look in the vector for duplicated values, then use the Erase–remove idiom to clean up the vector.
#include <vector>
#include <algorithm>
#include <iostream>
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
if (vec.size() < 2)
return;
for (int i = 0; i < vec.size() - 1;)
{
// This is for the case we emptied our vector
if (vec.size() < 2)
return;
// This heavily relies on the fact that this vector is sorted
if (vec[i] == vec[i + 1])
vec.erase(std::remove(vec.begin(), vec.end(), (int)vec[i]), vec.end());
else
i += 1;
}
// Since all duplicates are removed, the remaining elements in the vector are unique, thus the size of the vector
// But we are not returning anything or any reference, so I'm just gonna leave this here
// return vec.size()
}
int main()
{
std::vector<int> vec = {2, 3, 1, 5, 2, 2, 5, 1};
removeDuplicatesandElement(vec);
for (auto i : vec)
{
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}
Output: 3
Time complexity: O(n)

give how many numbers in a vector that are less than itself

i have to find how many other numbers are less than nums[i] and return them in another vector, for example [6,5,4,8] nums[0] = 6 so there is two numbers less than 6. so 2 would be pushed to the other vector. i am not getting 3 when it comes to checking the last element
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> nums2;
for(int i =0; i< nums.size(); ++i){
int max = nums[i];
int count = 0;
for(int j =0; j < nums.size(); ++j){
if(nums[j] < max && j!=0)
count++;
else
continue;
}
nums2.push_back(count);
}
return nums2;
}
};
You exclude the first element when counting in the condition:
if(nums[j] < max && j!=0)
// ^^ ---- remove this
There are algorithms that do want you need. std::transform transforms one range of values to another one and count_if counts how often a predicate returns true for a given range:
#include <vector>
#include <iostream>
#include <algorithm>
std::vector<size_t> count_if_smaller(const std::vector<int>& v) {
std::vector<size_t> result(v.size());
std::transform(v.begin(),v.end(),result.begin(),
[&](int x){
return std::count_if(v.begin(),v.end(),[&](int y){
return y < x;
});
} );
return result;
}
int main() {
std::vector<int> v{6,5,4,8};
auto r = count_if_smaller(v);
for (auto e : r) std::cout << e << " ";
}
One advantage of using algorithms is that you need not bother about indices of single elements. Introducing the same bug as in your code would be more difficult in the above. In other words, using algorithms is less error prone. Consider to use them when you can.
PS: Your current approach has complexity O(N^2). If you sort the input vector you could get O(N log N) easily.

Repeating elements in vector

I am a C++ student. And I need to solve this problem: "Write a program that receives a number and an array of the size of the given number. The program must find all the duplicates of the given numbers, push-back them to a vector of repeating elements, and print the vector". The requirements are I'm only allowed to use the vector library and every repeating element of the array must be pushed to the vector only once, e.g. my array is "1, 2, 1, 2, 3, 4...", the vector must be "1 ,2".
Here's what I've done so far. My code works, but I'm unable to make it add the same duplicate to the vector of repeating elements only once.
#include <iostream>
#include <vector>
int main() {
int n;
std::cin >> n;
int* arr = new int[n];
std::vector<int> repeatedElements;
for(int i = 0; i < n; ++i) {
std::cin >> arr[i];
}
for(int i = 0; i < n; ++i) {
bool foundInRepeated = false;
for(int j = 0; j < repeatedElements.size(); ++j) {
if(arr[i] == repeatedElements[j]) {
foundInRepeated = true;
break;
}
}
if(foundInRepeated) {
continue;
} else {
for(int i = 0; i < n; ++i) {
int count = 1;
for(int j = i + 1; j < n; ++j) {
if(arr[i] == arr[j]) {
++count;
}
}
if(count > 1) {
repeatedElements.push_back(arr[i]);
}
}
}
}
for(int i = 0; i < repeatedElements.size(); ++i) {
std::cout << repeatedElements[i] << " ";
}
std::cout << std::endl;
}
Consider what you're doing here:
if(foundInRepeated) {
continue;
} else {
for(int i = 0; i < n; ++i) { // why?
If the element at some index i (from the outer loop) is not found in repeatedElements, you're again iterating through the entire array, and adding elements that are repeated. But you already have an i that you're interested in, and hasn't been added to the repeatedElements. You only need to iterate through j in the else branch.
Removing the line marked why? (and the closing brace), will solve the problem. Here's a demo.
It's always good to follow a plan. Divide the bigger problem into a sequence of smaller problems is a good start. While this often does not yield an optimal solution, at least it yields a solution, which is more or less straightforward. And which subsequently can be optimized, if need be.
How to find out, if a number in the sequence has duplicates?
We could brute force this:
is_duplicate i = arr[i+1..arr.size() - 1] contains arr[i]
and then write ourselves a helper function like
bool range_contains(std::vector<int>::const_iterator first,
std::vector<int>::const_iterator last, int value) {
// ...
}
and use it in a simple
for (auto iter = arr.cbegin(); iter != arr.cend(); ++iter) {
if (range_contains(iter+1, arr.cend(), *iter) && !duplicates.contains(*iter)) {
duplicates.push_back(*iter);
}
}
But this would be - if I am not mistaken - some O(N^2) solution.
As we know, sorting is O(N log(N)) and if we sort our array first, we will
have all duplicates right next to each other. Then, we can iterate over the sorted array once (O(N)) and we are still cheaper than O(N^2). (O(N log(N)) + O(N) is still O(N log(N))).
1 2 1 2 3 4 => sort => 1 1 2 2 3 4
Eventually, while using what we have at our disposal, this could yield to a program like this:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using IntVec = std::vector<int>;
int main(int argc, const char *argv[]) {
IntVec arr; // aka: input array
IntVec duplicates;
size_t n = 0;
std::cin >> n;
// Read n integers from std::cin
std::generate_n(std::back_inserter(arr), n,
[](){
return *(std::istream_iterator<int>(std::cin));
});
// sort the array (in ascending order).
std::sort(arr.begin(), arr.end()); // O(N*logN)
auto current = arr.cbegin();
while(current != arr.cend()) {
// std::adjacent_find() finds the next location in arr, where 2 neighbors have the same value.
current = std::adjacent_find(current,arr.cend());
if( current != arr.cend()) {
duplicates.push_back(*current);
// skip all duplicates here
for( ; current != (arr.cend() - 1) && (*current == *(current+1)); current++) {
}
}
}
// print the duplicates to std::cout
std::copy(duplicates.cbegin(), duplicates.cend(),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}

Sorting vector elements in descending order

Please tell me what is wrong in my approach.
When I run the code, it is taking too long to compute to see the result.
#include <iostream>
#include <vector>
using namespace std;
vector<int> vec;
vector<int> sort(vector<int> x) {
vector<int> y;
int i = 1;
reset:for(i = 1; i <= x.size(); i++){
for (int j = 1; j <= x.size();) {
if (j == i) {
j++;
}
else {
if (x[i - 1] > x[j - 1]) {
j++;
}
else {
i++;
goto reset;
}
}
}
y.push_back(x[i - 1]);
x.erase(x.begin() + i - 1);
}
return y;
}
int main(){
vec.push_back(5);
vec.push_back(9);
vec.push_back(3);
vec.push_back(6);
vec.push_back(2);
for (int i = 1; i <= vec.size(); i++) {
cout << sort(vec)[i-1] << " ";
}
}
I am sorting this given sequence of 5 integers into descending order. Please help.
My plan was to search for the greatest integer in the whole vector x and move to it to the vector y and repeat the process.
Simple bubble-sort example
I think that your sort function is entering an infinite loop because of the goto reset statement. If you want to implement a simple bubble-sort algorithm, you can do it like this:
#include <iostream>
#include <utility>
#include <vector>
void bubble_sort(std::vector<int>& v) {
if(v.size() == 0) return;
for(int max = v.size(); max > 0; max--) {
for(int i = 1; i < max; i++) {
int& current = v[i - 1];
int& next = v[i];
if(current < next)
std::swap(current, next);
}
}
}
This function takes a vector, and for every consecutive pair of elements in the vector, if they're out of order, it swaps them. This results in the smallest element "bubbling" to the top of the vector. The process is repeated until all the elements are in order.
If we test it, we see that it prints the right answer:
int main() {
std::vector<int> test = {5, 9, 3, 6, 2};
bubble_sort(test);
for(int i : test) {
std::cout << i << ' ';
}
std::cout << '\n';
}
Using std::sort to do this faster
The standard library provides a sort function that'll sort pretty much anything. std::sort is really well implemented, it's more efficient than bubble sort, and it's really easy to use.
By default, std::sort orders things in ascending order, although it's easy to change it so that it works in descending order. There are two ways to do this. The first way sorts the vector using the reverse iterators (which allow you to pretend the vector is in reverse order), and the second way sorts the vector using std::greater, which tells std::sort to sort things in reverse order.
// Way 1:
std::sort(test.rbegin(), test.rend());
// Way 2:
auto compare_func = std::greater<>();
std::sort(test.begin(), test.end(), compare_func);
We can re-write the program using std::sort:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> test = {5, 9, 3, 6, 2};
auto compare_function = std::greater<>();
std::sort(test.begin(), test.end(), compare_function);
for(int i : test) {
std::cout << i << ' ';
}
std::cout << '\n';
}
Why can't you just use std:sort? You can do this:
sort(vec.begin(), vec.end(), [](const int a, const int b) {return a > b; }); //1
As suggested in the comments, there are two alternatives to the above:
std::sort(vec.begin(), vec.end(), std::greater<>()); //2
and:
std::sort(vec.rbegin(), vec.rend()); //3
(2) and (3) avoid a custom comparison function, and (2) is arguably more explicit about it's intent. But I was interested in the performance, and so I did a quick bench comparison of the three.
With Clang 12.0, (1) was fastest:
Clang results here
However, with GCC 10.3 all three were near identical:
GCC results here
Interesting results! With GCC, it's your choice as to which version you prefer; otherwise I would go for (1) or (2).

How to get index of first non zero value in a vector<int> in c++

What is the best way to do this.
For eg. I have
Vector<int> temp = {0,0,1,0,2}
I want to get the index of first non-zero value in the temp. So in this case I want answer 2.
I am already doing this, looking for a better way..
int index = -1;
for(int round=0; round < temp.size(); round++)
{
if(temp[round] > 0)
{
index = round;
break;
}
}
Thanks,
Gunjan
You can use:
distance( begin(temp), find_if( begin(temp), end(temp), [](auto x) { return x != 0; }));
This will return the size of the array if the item is not found. You will need #include <algorithm> and C++14 compilation mode. In C++11 you must replace auto with int or whatever type your container contains.
Here is a version with re-usable lambda, maybe slightly easier to read. Requires C++14.
Like the first answer, just use std::find_if_not instead of std::find_if.
bool IsZero(int i) {
return i == 0;
}
int main() {
vector<int> temp = {0, 0, 1, 0, 2};
auto it = find_if_not(a.begin(), a.end(), IsZero);
int first_nonzero_idx = distance(temp.begin(), it);
return first_nonzero_idx;
}
Output is:
2
You could use the following function:
int FindSmallerIndex(const std::vector<int> & vec)
{
int kMin=0;
while(vec[kMin]==0)
{
kMin += 1;
}
return kMin;
}
The simplest way is the obvious way:
int index = 0;
for(; index < temp.size(); index++) if(temp[index]) break;
if(index == temp.size()) {
//no such element
} else {
//first non-zero element is temp[index]
}
Any attempt to use stdlib-algorithms will just bloat your code.
More generic solution!
std::vector<int> a{0, 0, -1, 1, 0};
std::cout << std::distance(a.begin(),
std::find_if(a.begin(), a.end(),
[](const auto& x) { return x; }))
<< '\n';