I have two vectors vector a and vector b and I want to sort them both with the condition that a[i]/b[i]>a[i+1]/b[b+1]. How do I implement the code in C++ for that?
Say you start with
#include <vector>
#include <algorithm>
int main() {
std::vector<int> a{2, 7, 3};
std::vector<int> b{4, 2, 1};
Create a vector of indices, inds:
std::vector<std::size_t> inds;
for(std::size_t i = 0; i < a.size(); ++i)
inds.push_back(i);
also create a comparison function describing the criteria in your question:
auto cmp = [&](std::size_t lhs, std::size_t rhs) {
return static_cast<double>(a[lhs]) / b[lhs] > static_cast<double>(a[rhs]) / b[rhs];
};
and sort according to it:
std::sort(std::begin(inds), std::end(inds), cmp);
}
At this point, inds will be organized according to your criteria.
Finally, use the answers in reorder a vector using a vector of indices to reorder each of a and b according to inds.
Related
I have a vector containing instances of a class, let's say std::vector<A> a. I want to order this vector according to weights stored in a std::vector<float> weights, with weights[i] being the weight associated to a[i]; after sorting, a elements must be ordered by increasing weight.
I know how to do this explicitly, but I'd like to use C++14 STL algorithms in order to benefit from an eventual optimal implementation. Up to now, I haven't been able to figure how to use weights in a lambda comparison expression for std::sort, nor how to keep a and weights aligned every time two elements of a are swapped by std::sort, so I'm beginning to think that it might be not possible.
Thanks in advance for any help.
Sort an index vector, then rearrange according to the result:
void my_sort(std::vector<A>& a, std::vector<float>& weights)
{
std::vector<int> idx(a.size());
std::iota(idx.begin(), idx.end(), 0);
sort(idx.begin(), idx.end(),
[&](int a, int b) { return weights[a] < weights[b]; });
auto reorder = [&](const auto& o) {
decltype(o) n(o.size());
std::transform(idx.begin(), idx.end(), n.begin(),
[&](int i) { return o[i]; });
return n;
};
a = reorder(a);
weights = reorder(weights);
}
Transform the two vectors in a std::pair<A,float> vector and then sort based on the weight ( second member of the pair ) . Recreate the two vectors afterwards
Add a new member to the A class so that it contains the weight and sort based on that weight
make a custom comparison function based on a global array containing the weights like described here: std::sort and custom swap function
I would go for 3 as it is the most efficient. That is valid if you don't have multi-threading which would require some synchronization.
With my comment I was alluding exactly to what #AndreaRossini summarised with their comment. Something like this:
#include <boost/hana/functional/on.hpp>
#include <functional>
#include <iostream>
#include <range/v3/algorithm/sort.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/zip.hpp>
#include <string>
#include <vector>
using boost::hana::on;
using namespace ranges;
using namespace ranges::views;
// helpers to get first and second of a pair
auto /*C++17->*/constexpr/*<-C++17*/ fst = [](auto const& p){ return p.first; };
auto /*C++17->*/constexpr/*<-C++17*/ snd = [](auto const& p){ return p.second; };
int main(){
std::vector<std::string> v{"one", "two", "three"}; // values
std::vector<float> w{3,1,2}; // weights
// zipping the two sequences; each element of vw is a pair
auto vw = zip(v, w);
// sorting: using `std::less` on the `snd` element of the pairs
sort(vw, std::less<>{} ^on^ snd);
// extracting only the `fst` of each pair
auto res = vw | transform(fst);
// show result
for (auto i : res) { std::cout << i << std::endl; }
}
A few things about the libraries that I've used:
res is not a std::vector but just a view; if you want a vector, you can do
#include <range/v3/range/conversion.hpp>
auto res = vw | transform(fst) | to_vector;
std::less<>{} ^on^ snd is equivalent to the following f
auto f = [](auto const& x, auto const& y){
return std::less<>{}(snd(x), snd(y));
};
so you can think of it as a function that takes x and y and gives back snd(x) < snd(y).
I have two vectors. I want to make a new vector which contains the values of these two vectors. I found that a fast way can be use as
vector<int> original_vector
vector<int> copy_to_vector(original_vector)
However, it does not show how to copy two vectors (above only for one to other). Now my problem is
vector<int> original_vector1
vector<int> original_vector2
//Copy original_vector1 and original_vector2 to copy_to_vector
// Note that original_vector1 or original_vector2 maybe empty
vector<int> copy_to_vector
How can I do it in C++. I am using g++ in Ubuntu
My current solution is
std::vector<U32> copy_to_vector(original_vector1);
copy_to_vector.insert(copy_to_vector.end(), original_vector2.begin(), original_vector2.end());
vector<int> copy_to_vector(original_vector1)
copy_to_vector.reserve(original_vector1.size() + original_vector2.size());
copy_to_vector.insert( copy_to_vector.end(), original_vector2.begin(), original_vector2.end());
This solution works fine if one of the vectors or both of them are empty
live demo
It's often a good idea to encapsulate operations like this in a utility function.
RVO takes are of eliding the copy of the return value so this code is as efficient as inlining the operations, but more maintainable and easier to reason about:
#include <iostream>
#include <vector>
#include <algorithm>
// utility function to return a new vector which is the
// result of v1 with v2 appended. order is preserved
std::vector<int> combine(const std::vector<int>& v1,
const std::vector<int>& v2)
{
std::vector<int> result;
result.reserve(v1.size() + v2.size());
result = v1;
result.insert(result.end(), v2.begin(), v2.end());
return result;
}
int main()
{
using namespace std;
vector<int> x = { 1, 2, 3 };
vector<int> y = { 4, 5, 6 };
auto z = combine(x, y);
copy(begin(z), end(z), ostream_iterator<int>(cout, "\n"));
return 0;
}
Use std::back_inserter
#include <iterator> // back_inserter
#include <algorithm> // copy
vector<int> copy_to_vector;
copy_to_vector.reserve( original_vector1.size() + original_vector2.size() ) // reserve memory for both vectors at once
copy_to_vector = original_vector1;
std::copy(original_vector2.begin(),original_vector2.end(),std::back_inserter(copy_to_vector));
I want to add a value multiple times to an std::vector. E.g. add the interger value 1 five times to the vector:
std::vector<int> vec;
vec.add(1, 5);
vec should be of the form {1,1,1,1,1} afterwards. Is there a clean c++ way to do so?
It really depends what you want to do.
Make a vector of length 5, filled with ones:
std::vector<int> vec(5, 1);
Grow a vector by 5 and fill it with ones:
std::vector<int> vec;
// ...
vec.insert(vec.end(), 5, 1);
Or resize it (if you know the initial size):
std::vector<int> vec(0);
vec.resize(5, 1);
You can also fill with elements using one of the many versions of fill, for example:
fill_n(back_inserter(vec), 5, 1);
and so on.... Read the library documentation, some of these functions return useful information, too.
Just use std::vector::insert.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> a;
a.insert(a.end(), 5, 1);
for(auto const& e : a)
std::cout << e << std::endl;
return 0;
}
You can just use the std::vector constructor for this:
std::vector<int> vec (5,1);
The signature for this is:
vector (size_type n, const value_type& val)
The standard algorithm header has a number of functions which can be used in cases like this. std::fill_n would work for your case.:
std::fill_n (std::back_inserter(vec), 5, 1);
You can use the assign method:
vec.assign(5, 1);
This will delete any existing elements in the vector before adding the new ones.
Can you please tell me how to do the following using STL algorithms?
// Create a vector of 50 elements, and assign elem value same as index value
std::vector<int> a(50);
for (int i = 0; i < a.size(); i++)
{
a[i] = i;
}
// Create another vector by copying a section of vector a
std::vector<int> b;
size_t ind = 20;
b.resize(a.size() - ind);
for (int i = 0; i < b.size(); i++)
{
b[i] = a[i+ind];
}
Essentially, I am trying to create a new vector b, from vector a, by skipping the first 'ind' elements of a.
I'd probably do it something like this:
std::vector<int> a(50);
// fill a with 0..N
std::iota(a.begin(), a.end(), 0);
size_t ind = 20;
// initialize `b` from elements of `a`:
std::vector<int> b{a.begin()+ind, a.end()};
You could use std::copy for the second part, but for the case at hand I'd prefer to initialize b from the iterators as I've done above.
With boost you could do the first part with initialization as well (see Jerry's answer).
auto r = boost::irange(0,50);
auto a = std::vector<int>(std::begin(r), std::end(r));
Eric Neibler's range library I think includes this type of thing and I fully expect it'll make it into C++17. Until then you have to use his or boost's as a third-party lib.
Use the
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
constructor as follows.
auto start = std::next(a.begin(), 20);
std::vector<int> b(start, a.end());
I want to use a special method to initialize a std::vector<unsigned int> which is described in a C++ book I use as a reference (the German book 'Der C++ Programmer' by Ulrich Breymann, in case that matters). In that book is a section on sequence types of the STL, referring in particular to list, vector and deque. In this section he writes that there are two special constructors of such sequence types, namely, if Xrefers to such a type,
X(n, t) // creates a sequence with n copies of t
X(i, j) // creates a sequence from the elements of the interval [i, j)
I want to use the second one for an interval of unsigned int, that is
std::vector<unsigned int> l(1U, 10U);
to get a list initialized with {1,2,...,9}. What I get, however, is a vector with one unsigned int with value 10 :-| Does the second variant exist, and if yes, how do I force that it is called?
there are at least three ways that you can do that. One was mentioned earlier by Brian
//method 1
generate(v.begin(), v.end(), [] { static int i {1}; return i++; });
You can also use std::iota if you are using c++11
//method 2
iota(v.begin(), v.end(), 1);
Or instead you can initialize your container with 1s and then do a partial sum on that. I don't think anybody will use this third method anyway :)
//method 3
vector<int> v(n, 1);
partial_sum(v.begin(), v.end(), v.begin());
Reread the paragraphs near there describing what each of the parameters are. Specifically, it should mention that i and j are not values, but iterators. This constructor is very commonly used to make copies of other types of containers. If you want to get a sequence of values, the Boost library provides a counting iterator, that does exactly what you want.
std::vector<unsigned int> numbers(
boost::counting_iterator<unsigned int>(0U),
boost::counting_iterator<unsigned int>(10U));
A non-boost way to do this with a self-incrementing iterator.
#include <vector>
#include <iostream>
#include <algorithm>
static int NUM_ITEMS = 10;
class gen_range {
public:
gen_range(int i) { idx = i; }
int operator()() { return (idx++); };
int idx;
};
int main() {
std::vector<int> x(NUM_ITEMS);
std::generate_n(x.begin(), NUM_ITEMS, gen_range(0));
for (int i=0; i < x.size(); i++) {
std::cout << x[i] << std::endl;
}
}
C++11:
std::vector<int> idxs (n);
std::generate_n (idxs.begin (), n, [] { static int i {1}; return i++; });
No, that variant does not exist. The second constructor initializes a vector from two iterators that point into another sequence.
Here is an example of the "two-iterator" constructor in action:
int fill_data[4] = { 1, 2, 3, 4 };
std::vector<int> v(fill_data, fill_data + 4);