How to compare vector with array? - c++

I would like to compare vector with an array. Elements in vector and in array are in different order, unsorted and can duplicated. E.g.
Below are the same:
vector<int> lvector = {5,7,3,1,2,7};
int larray[6] = {3,5,1,7,2,7}
Below, not the same:
vector<int> lvector = {5,7,3,1,2,7,5};
int larray[7] = {3,5,1,7,2,7,3}
And something like this is also not the same:
vector<int> lvector = {1,1,1,1,2,2};
int larray[6] = {1,1,1,1,1,2}
Now I need to check if vector and array have got the same elements. I can't modify the vector and the array, but I can create a new container and copy the element from vector and array to this new container and then copare them. I am asking about this, because I would like to do this in en efficient way. Thanks.

That's a variant of what proposed by soon:
#include <iostream>
#include <unordered_set>
#include <vector>
int main()
{
std::vector<int> v{5, 7, 3, 1, 2, 7};
int arr[] = {3, 5, 1, 7, 2, 7};
std::vector<int> mv(std::begin(v), std::end(v));
std::vector<int> ma(std::begin(arr), std::end(arr));
std::sort(mv.begin(), mv.end()) ;
std::sort(ma.begin(), ma.end()) ;
std::cout << "Are equal? " << (mv == ma) << std::endl;
return 0;
}

There are a lot of different ways of solving this problem, each has proc and cons.
Some pre-tests
Obviously, two ranges cannot be equal, if they have different size.
You could calculate an order independent hash function for elements in the ranges (thanks, #Michael Anderson). It could be a sum of elements, or you just could xor them all. Arrays with different hash value cannot be equal.
std::unordered_multiset
You could create an unordered_multiset, which holds frequency of elements in the range. While it has linear complexity in average, it may be O(n^2) because of hash collisions. Quote from the Standard (N3337, § 23.5.7.2):
Complexity: Average case linear, worst case quadratic.
However, you should also remember the complexity of std::unordered_set::operator==:
For unordered_set and unordered_map, the complexity of
operator== (i.e., the number of calls to the == operator of the
value_type, to the predicate returned by key_equal(), and to the
hasher returned by hash_function()) is proportional to N in the
average case and to N^2 in the worst case, where N is a.size().
For unordered_multiset and unordered_multimap, the complexity of
operator== is proportional to sum of Ei^2 in the average case and
to N^2 in the worst case, where N is a.size(), and Ei is the
size of the ith equivalent-key group in a.
However, if the
respective elements of each corresponding pair of equivalent-key
groups Eai and Ebi are arranged in the same order (as is commonly
the case, e.g., if a and b are unmodified copies of the same
container), then the average-case complexity for unordered_multiset
and unordered_multimap becomes proportional to N (but worst-case
complexity remains O(N2), e.g., for a pathologically bad hash
function).
Example:
#include <iostream>
#include <unordered_set>
#include <vector>
int main()
{
std::vector<int> v{5, 7, 3, 1, 2, 7};
int arr[] = {3, 5, 1, 7, 2, 7};
std::unordered_multiset<int> mv(std::begin(v), std::end(v));
std::unordered_multiset<int> ma(std::begin(arr), std::end(arr));
std::cout << "Are equal? " << (mv == ma) << std::endl;
return 0;
}
std::sort
You could compare sorted copies of your range. According to the Standard (N3337, § 25.4.1.1) , it has O(n * log(n)) complexity:
Complexity: O(N log(N)) (where N == last - first) comparisons.
Example:
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v{5, 7, 3, 1, 2, 7};
int arr[] = {3, 5, 1, 7, 2, 7};
std::vector<int> sv(v);
std::vector<int> sa(std::begin(arr), std::end(arr));
std::sort(std::begin(sv), std::end(sv));
std::sort(std::begin(sa), std::end(sa));
std::cout << "Are equal? " << (sv == sa) << std::endl;
return 0;
}

Here is template function to compare vector with array:
#include <array>
#include <algorithm>
#include <vector>
template <class T, std::size_t N>
bool equal(const std::vector<T>& v, const std::array<T, N>& a)
{
if (v.size() != N)
return false;
return std::equal(v.begin(), v.end(), a.begin());
}
Usage example:
std::vector<int> v = {1, 2, 3};
std::array<int, 4> a = {1, 2, 3, 4};
bool eq = equal(v, a);

At first convert the array into v1 vector.
v={1,1,2,3,4}; vector and
v1={1,1,2,3,4}; converted from array
bool f=0;
if(equal(v.begin(),v.end(),v1.begin())) //compare two vector, if equal return true
{
f=1;
}
}
if(f==1)
cout<<"Yes"<<endl;
else cout<<"No"<<endl;

Related

C++ vector sorting and mapping from unsorted to sorted elements

I have to perform the following task. Take a std::vector<float>, sort the elements in descending order and have an indexing that maps the unsorted elements to the sorted ones. Please note that the order really matters: I need a map that, given the i-th element in the unsorted vector, tells me where this element is found in the sorted one. The vice-versa has been achieved already in a pretty smart way (through c++ lambdas) e.g., here: C++ sorting and keeping track of indexes. Nevertheless, I was not able to find an equally smart way to perform the "inverse" task. I would like to find a fast way, since this kind of mapping has to be performed many times and the vector has big size.
Please find in the following a simple example of what I need to achieve and my (probably suboptimal, since it relies on std::find) solution of the problem. Is it the most fast/efficient way to perform this task? If not, are there better solutions?
Example
Starting vector: v = {4.5, 1.2, 3.4, 2.3}
Sorted vector: v_s = {4.5, 3.4, 2.3, 1.2}
What I do want: map = {0, 3, 1, 2}
What I do not want: map = {0, 2, 3, 1}
My solution
template <typename A> std::vector<size_t> get_indices(std::vector<A> & v_unsorted, std::vector<A> & v_sorted) {
std::vector<size_t> idx;
for (auto const & element : v_unsorted) {
typename std::vector<A>::iterator itr = std::find(v_sorted.begin(), v_sorted.end(), element);
idx.push_back(std::distance(v_sorted.begin(), itr));
}
return idx;
}
Thanks a lot for your time, cheers!
You can use the code below.
My version of get_indices does the following:
Create a vector of indices mapping sorted -> unsorted, using code similar to the one in the link you mentioned in your post (C++ sorting and keeping track of indexes).
Then by traversing those indices once, create the sorted vector, and the final indices mapping unsorted -> sorted.
The complexity is O(n * log(n)), since the sort is done in O(n * log(n)), and the final traversal is linear.
The code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
template <typename T>
std::vector<size_t> get_indices(std::vector<T> const & v_unsorted, std::vector<T> & v_sorted)
{
std::vector<size_t> idx_sorted2unsorted(v_unsorted.size());
std::iota(idx_sorted2unsorted.begin(), idx_sorted2unsorted.end(), 0);
// Create indices mapping (sorted -> unsorted) sorting in descending order:
std::stable_sort(idx_sorted2unsorted.begin(), idx_sorted2unsorted.end(),
[&v_unsorted](size_t i1, size_t i2)
{ return v_unsorted[i1] > v_unsorted[i2]; }); // You can use '<' for ascending order
// Create final indices (unsorted -> sorted) and sorted array:
std::vector<size_t> idx_unsorted2sorted(v_unsorted.size());
v_sorted.resize(v_unsorted.size());
for (size_t i = 0; i < v_unsorted.size(); ++i)
{
idx_unsorted2sorted[idx_sorted2unsorted[i]] = i;
v_sorted[i] = v_unsorted[idx_sorted2unsorted[i]];
}
return idx_unsorted2sorted;
}
int main()
{
std::vector<double> v_unsorted{ 4.5, 1.2, 3.4, 2.3 };
std::vector<double> v_sorted;
std::vector<size_t> idx_unsorted2sorted = get_indices(v_unsorted, v_sorted);
for (auto const & i : idx_unsorted2sorted)
{
std::cout << i << ", ";
}
return 0;
}
Output:
0, 3, 1, 2,
Once you have the mapping from sorted to unsorted indices, you only need a loop to invert it.
I am building on the code from this answer: https://stackoverflow.com/a/12399290/4117728. It provides a function to get the vector you do not want:
#include <iostream>
#include <vector>
#include <numeric> // std::iota
#include <algorithm> // std::sort, std::stable_sort
using namespace std;
template <typename T>
vector<size_t> sort_indexes(const vector<T> &v) {
// initialize original index locations
vector<size_t> idx(v.size());
iota(idx.begin(), idx.end(), 0);
// sort indexes based on comparing values in v
// using std::stable_sort instead of std::sort
// to avoid unnecessary index re-orderings
// when v contains elements of equal values
stable_sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
return idx;
}
Sorting the vector is O(N logN) your code calls find N times resulting in O(N*N). On the other hand, adding a single loop is only linear, hence sorting plus the loop is still O(N log N).
int main() {
std::vector<double> unsorted{4.5, 1.2, 3.4, 2.3};
auto idx = sort_indexes(unsorted);
for (auto i : idx) std::cout << unsorted[i] << "\n";
// the vector you do not want
for (auto i : idx) std::cout << i << "\n";
// invert it
std::vector<size_t> idx_inverse(idx.size());
for (size_t i=0;i<idx.size();++i) idx_inverse[ idx[i] ] = i;
// the vector you do want
for (auto i : idx_inverse) std::cout << i << "\n";
}
Live Demo

How to compare two vectors for equality?

I have the following program:
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> nums2 = {5, 4, 3, 2, 1};
bool equal = std::equal(nums.begin(), nums.end(), nums2.begin());
if (equal)
{
cout << "Both vectors are equal" << endl;
}
There are two vectors that have equal elements. std::equal function does not work here because it goes sequentially and compares corresponding elements. Is there a way to check that both these vectors are equal and get true in my case without sorting? In real example I do not have integers but custom objects which comparing as equality of pointers.
You can construct a std::unordered_set from each vector, then compare those, as shown in the code snippet below:
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main()
{
std::vector<int> nums = { 1, 2, 3, 4, 5 };
std::vector<int> nums2 = { 5, 4, 3, 2, 1 };
std::vector<int> nums3 = { 5, 4, 9, 2, 1 };
std::unordered_set<int> s1(nums.begin(), nums.end());
std::unordered_set<int> s2(nums2.begin(), nums2.end());
std::unordered_set<int> s3(nums3.begin(), nums3.end());
if (s1 == s2) {
std::cout << "1 and 2 are equal";
}
else {
std::cout << "1 and 2 are different";
}
std::cout << std::endl;
if (s1 == s3) {
std::cout << "1 and 3 are equal";
}
else {
std::cout << "1 and 3 are different";
}
std::cout << std::endl;
return 0;
}
However, there are some points to bear in mind:
For vectors of custom type objects, you would need to provide an operator== for that type (but that would have to be done anyway, or how can you say if the two vectors have the same contents).
Vectors that containing duplicate entries will create sets that have those duplicates removed: Thus, {1, 2, 2, 3} will show equal to {1, 2, 3}.
You will also need to provide a std:hash for your custom type. For a trivial class, bob, which just wraps an integer, that hash, and the required operator==, could be defined as shown below; you can then replace the <int> specializations in the above example with <bob> and it will work. (This cppreference article explains more about the hash.)
class bob {
public:
int data;
bob(int arg) : data{ arg } { }
};
bool operator==(const bob& lhs, const bob& rhs)
{
return lhs.data == rhs.data;
}
template<> struct std::hash<bob> {
std::size_t operator()(bob const& b) const noexcept {
return static_cast<size_t>(b.data);
}
};
The std::is_permutation standard library algorithm does exactly what you want. It returns true if both ranges contain the same elements in any order.
It might be slow for some applications but it only requires equality comparison and it doesn't require a temporary container or additional memory allocation.
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> nums = { 1, 2, 3, 4, 5 };
std::vector<int> nums2 = { 5, 4, 3, 2, 1 };
bool equal = std::is_permutation(nums.begin(), nums.end(), nums2.begin(), nums2.end());
if (equal) {
std::cout << "Both vectors are equal" << std::endl;
}
}
You're looking for a set or a multiset. C++ standard library does have implementations of these data structures:
std::set
std::multiset
std::unordered_set
std::unordered_multiset
If I had to invent an algorithm to do this from scratch, because for whatever reason using sets or sorts doesn't work, I would consider removing matches. This will be inefficient - it's O(n^2) - but it will work, and inefficiency is unlikely to be an issue in many cases:
bool compare(A, B)
copy B to BB
for each a in A
if BB contains a
remove a from BB
else
return false
if BB is empty
return true
return false
Throwing-in one more way to solve your task, using std::sort. It also works correctly if vectors have duplicate elements (as seen from example below). It is also quite fast, O(N*Log(N)) time on average, in real life will be close in time to solutions with std::unordered_set or std::unordered_multiset.
Yes, I see that OP asked to achieve without sorting, but actually std::is_permutation is also doing sorting underneath almost for sure. And std::set does indirectly sorting too using trees. Even std::unordered_set does a kind of sorting by hash value (hash bucketing is a kind of radix sorting). So probably this task can't be solved without a kind of indirect sorting or other kind of ordering whole vector.
Try it online!
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums1 = {1, 2, 3, 4, 1, 5}, nums2 = {5, 4, 3, 1, 2, 1};
std::sort(nums1.begin(), nums1.end());
std::sort(nums2.begin(), nums2.end());
std::cout << std::boolalpha << (nums1 == nums2) << std::endl;
}
Output:
true

How can I find the index of the highest value in a vector, defaulting to the greater index if there are two "greatest" indices?

I have been using std::max_element(vec), but from what I can tell, it returns the smallest index if two "greatest" indices are equal.
Example:
vector<int> v = {1, 2, 3, 4, 5, 3, 3, 2, 5};
std::max_element(v) would reference v[4], but for the purposes of my project I need it to reference v[8] instead. What would be the best way to do this?
You can use this
max_element(v.rbegin(), v.rend());
to refer to the greatest index of the greatest value.
For example,
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
int main()
{
vector<int> v = {1, 2, 3, 4, 5, 3, 3, 2, 5};
*max_element(v.rbegin(), v.rend())=-1;
for (auto i: v) cout << i << ' ';
}
produces output
1 2 3 4 5 3 3 2 -1
The method mentioned above returns a reverse iterator, as pointed out by #BoBTFish. To get a forward iterator, you could do this:
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
int main()
{
vector <int> v = {1, 2, 3, 4, 5, 3, 3, 2, 5};
reverse_iterator < vector <int> :: iterator > x (max_element(v.rbegin(), v.rend()));
vector <int> :: iterator it=--x.base(); // x.base() points to the element next to that pointed by x.
*it=-1;
*--it=0; // marked to verify
for (auto i: v) cout << i << ' ';
}
produces output
1 2 3 4 5 3 3 0 -1
^
It can be seen that the iterator it is a forward iterator.
It's very easy to make your own function:
/* Finds the greatest element in the range [first, last). Uses `<=` for comparison.
*
* Returns iterator to the greatest element in the range [first, last).
* If several elements in the range are equivalent to the greatest element,
* returns the iterator to the last such element. Returns last if the range is empty.
*/
template <class It>
auto max_last(It first, It last) -> It
{
auto max = first;
for(; first != last; ++first) {
if (*max <= *first) {
max = first;
}
}
return max;
}

Counting number of distinct integers in array

To find the number of distinct numbers in an array from the lth to the rth index, I wrote a code block like:
int a[1000000];
//statements to input n number of terms from user in a.. along with l and r
int count=r-l+1; //assuming all numbers to be distinct
for(; l<=r; l++){
for(int i=l+1; i<=r; i++){
if(a[l]==a[i]){
count--;
break;
}
}
}
cout<<count<<'\n';
Explanation
For an array say, a=5 6 1 1 3 2 5 7 1 2 of ten elements. If we wish to check the number of distinct numbers between a[1] and a[8] that is the second and the 9th elements (including both), The logic I tried to implement would first take count=8 (no. of elements to be considered) and then it starts from a[1] that is 6 and checks for any other 6 after it, if it does find, it decreases the count by one and goes on for the next number in the row. So that if there are any more occurrence of 6 after that one, it would not be included twice.
Problem I tried small test cases and it works. But when I tried with bigger data, it did not work, so I wanted to know where would my logic fail?
Bigger data, as in integrated with other parts of the program and then used. Which gave incorrect output
You can try to use std::set
Basic idea is to add all the elements into your new set, and just output the size of your set.
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main()
{
int l = 1, r = 6;
int arr[] = {1, 1, 2, 3, 4, 5, 5, 5, 5};
set<int> s(&arr[l], &arr[r + 1]);
cout << s.size() << endl;
return 0;
}
Here is an answer that does not use std::set, although that solution is probably simpler.
#include <algorithm>
#include <vector>
int main()
{
int input[10]{5, 6, 1, 1, 3, 2, 5, 7, 1, 2}; //because you like raw arrays, I guess?
std::vector<int> result(std::cbegin(input), std::cend(input)); //result now contains all of input
std::sort(std::begin(result), std::end(result)); //result now holds 1 1 1 2 2 3 5 5 6 7
result.erase(std::unique(std::begin(result), std::end(result)), std::end(result)); //result now holds 1 2 3 5 6 7
result.size(); //gives the count of distinct integers in the given array
}
Here it is live on Coliru if you're into that.
--
EDIT: Here, have a short version of the set solution, too.
#include <set>
int main()
{
int input[10]{5, 6, 1, 1, 3, 2, 5, 7, 1, 2}; //because you like raw arrays, I guess?
std::set<int> result(std::cbegin(input), std::cend(input));
result.size();
}
The first question to ask with this type of problem is what is the possible range of the values. if the range of numbers N is "reasonably small", then you can use a boolean array of size N to indicate whether the number corresponding to the index is present. You iterate from l to r, setting the flag, and if the flag was not already set increment a counter.
count = 0;
for(int i=l; i<=r; i++) {
if (! isthere[arr[i]]) {
count++;
isthere[arr[i]] = TRUE;
}
}
In terms of complexity, both this approach and the one based on set are O(n), but this one is faster as there is no hashing involved. For small N, for example for numbers between 0-255, most likely this is also likely to be less memory intensive. For larger N, for example if any 32-bit integers is allowed, the set based approach is more suitable.
You said you didn't mind another solution. So here it is. It uses set - a structure that stores only unique elements. By the way, on the bigger data - it will much faster than solution with two cycles.
set<int> a1;
for (int i = l; i <= r; i++)
{
a1.insert(a[i]);
}
cout << a1.size();
In the below process I'm giving process of counting unique numbers. In this technique you just get unique elements in an array. this process will update your array with garbage value. So in this process you can't use this array (that we will use) further anymore. This array will automatically resize with distinct elements.
#include <stdio.h>
#include <iostream>
#include <algorithm> // for using unique (library function)
int main(){
int arr[] = {1, 1, 2, 2, 3, 3};
int len = sizeof(arr)/sizeof(*arr); // finding size of arr (array)
int unique_sz = std:: unique(arr, arr + len)-arr; // Counting unique elements in arr (Array).
std:: cout << unique_sz << '\n'; // Printing number of unique elements in this array.
return 0;
}
If you want to handle that problem (That I told before), you can follow this process. You can handle this by coping your array in another array.
#include <stdio.h>
#include <iostream>
#include <algorithm> // for using copy & unique (library functions)
#include <string.h> // for using memcpy (library function)
int main(){
int arr[] = {1, 1, 2, 2, 3, 3};
int brr[100]; // we will copy arr (Array) to brr (Array)
int len = sizeof(arr)/sizeof(*arr); // finding size of arr (array)
std:: copy(arr, arr+len, brr); // which will work on C++ only (you have to use #include <algorithm>
memcpy(brr, arr, len*(sizeof(int))); // which will work on C only
int unique_sz = std:: unique(arr, arr+len)-arr; // Counting unique elements in arr (Array).
std:: cout << unique_sz << '\n'; // Printing number of unique elements in this array.
for(int i=0; i<len; i++){ // Here is your old array, that we store to brr (Array) from arr (Array).
std:: cout << brr[i] << " ";
}
return 0;
}
Personally, I'd just use standard algorithms
#include<algorithm>
#include <iostream>
int main()
{
int arr[] = {1, 1, 2, 3, 4, 5, 5, 5, 5};
int *end = arr + sizeof(arr)/sizeof(*arr);
std::sort(arr, end);
int *p = std::unique(arr, end);
std::cout << (int)(p - arr) << '\n';
}
This obviously relies on being allowed to modify the array (any duplicates are moved to the end of arr). But it is easy to create a copy of an array if needed and work on the copy.
TL;DR: Use this:
template<typename InputIt>
std::size_t countUniqueElements(InputIt first, InputIt last) {
using value_t = typename std::iterator_traits<InputIt>::value_type;
return std::unordered_set<value_t>(first, last).size();
}
There are two approaches:
Insert everything into a set, count the set. Because you don't care about the order you can use a std::unordered_set which will be faster than std::set. std::set is implemented as a tree which does a lot of allocations so it can be slow.
Use std::sort. If you want to preserve the original array you'll need to make a copy of it.
Here is a complete example.
#include <algorithm>
#include <cstdint>
#include <vector>
#include <unordered_set>
#include <iostream>
template<typename RandomIt>
std::size_t countUniqueElementsSort(RandomIt first, RandomIt last) {
if (first == last)
return 0;
std::sort(first, last);
std::size_t count = 1;
auto val = *first;
while (++first != last) {
if (*first != val) {
++count;
}
val = *first;
}
return count;
}
template<typename InputIt>
std::size_t countUniqueElementsSet(InputIt first, InputIt last) {
using value_t = typename std::iterator_traits<InputIt>::value_type;
return std::unordered_set<value_t>(first, last).size();
}
int main() {
std::vector<int> v = {1, 3, 4, 4, 3, 6};
std::cout << countUniqueElementsSet(v.begin(), v.end()) << "\n";
std::cout << countUniqueElementsSort(v.begin(), v.end()) << "\n";
int v2[] = {1, 3, 4, 4, 3, 6};
std::cout << countUniqueElementsSet(v2, v2 + 6) << "\n";
std::cout << countUniqueElementsSort(v2, v2 + 6) << "\n";
}
Using that loop in the sort version should be faster than std::unique.
The complexity of 2. is worse than 1. - the average case is O(N) vs O(N log N). But it avoids allocation so may end up being faster for small arrays or ones that are already sorted or mostly already sorted.
You should definitely not use std::set, and probably not use std::unique (though it does lead to fewer lines of code, and won't make that much difference to performance so up to you).
In any case, in most cases you should go with the set version - it's a lot simpler simpler and should be faster in almost all cases.
As other people have mentioned, if you know your input domain is small you can use a bool array instead of an unordered_set.

How can I sort a portion of std::list?

#include <iostream>
#include <list>
#include <algorithm>
int main()
{
std::list<int> numbers = {1, 3, 0, -8, 5, 3, 1};
auto positionInMiddle = std::find(numbers.begin(), numbers.end(), -8);
std::sort(positionInMiddle, numbers.end()); // This doesn't work,
// Needs random access iterator.
numbers.sort(); // This sorts the entire list.
for (int i : numbers)
std::cout << i << std::endl;
return 0;
}
Is there some trick I can use? For example if there was a method that swaps two nodes in the list, then I could use mergesort.
Lists have constant time insertions and removal, so making a temporary list with splice to sort is quite fast insertion wise (still linear in copying elements, unfortunately):
#include <iostream>
#include <list>
#include <algorithm>
int main()
{
std::list<int> numbers = {1, 3, 0, -8, 5, 3, 1};
auto positionInMiddle = std::find(numbers.begin(), numbers.end(), -8);
std::list<int> temp;
temp.splice(temp.end(), numbers, positionInMiddle, numbers.end());
temp.sort();
numbers.splice(numbers.end(), temp, temp.begin(), temp.end());
for (int i : numbers)
std::cout << i << std::endl;
return 0;
}
You can't use std::sort to sort std::list, because std::sort requires iterators to be random access, and std::list iterators are only bidirectional.
However, std::list has a member function sort that will sort it: