How to call swap() algorithm on std::list elements? - c++

I'm trying to swap the 2nd and 4th elements in a list, but I can't figure out how to do this. I tried to use vector notation, but it didn't work.
list<int> a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
swap(a1[1], a1[3]);

A std::list doesn't provide random access indexing, like a std::vector or an array does. You need to use iterators instead, eg:
auto first_node = a1.begin();
auto second_node = std::next(first_node);
auto fourth_node = std::next(first_node, 3);
std::swap(*second_node, *fourth_node);

Related

Too many initializer values; Initializing Dynamically Allocated Arrays?

Recently while going over C++, I dynamically allocated space for an array and tried to initialize it with 8 default values on the next line.
int* intArray = new int[8];
intArray = {1, 2, 3, 4, 5, 6, 7, 8};
Visual Studio didn't like that, and underlined the 2 in red, as if there is a problem there, only to give me the error "too many initializer values"
I don't know if I used incorrect syntax or if you're just not allowed to set the value of an array that way after declaration. Any ideas?
Okay, it seems this also isn't working for regular non-pointer arrays too, I must be just doing something dumb.
intArray is not an array, it's a pointer. A pointer can't be initialized with an initializer list.
Dynamic allocated memory can be initialized at the moment of allocation:
int* intArray = new int[8] {1, 2, 3, 4, 5, 6, 7, 8};
C array can be initialized also at the declaration:
int intArray[8] = {1, 2, 3, 4, 5, 6, 7, 8};
C++ allows static allocation without dimension parameter
int intArray[] = {1, 2, 3, 4, 5, 6, 7, 8};
where for dynamic allocation
int *intArray = new int[8] {1, 2, 3, 4, 5, 6, 7, 8};
the matching dimension must be passed.

can i add a number to range of elements in numper array without loops c++

I want to add a certain constant value to range of elements in an array without iterating over them , can i do that ?
Example:
int arr[5] = {1, 2, 3, 4, 5};
add_certain_val(arr, 0, 4, 2);
// now arr == {3, 4, 5, 6, 7};
You can perform the addition without a loop by specifying each element individually:
int array[] = {1, 2, 3, 4, 5};
array[0] += 2;
array[1] += 2;
array[2] += 2;
array[3] += 2;
array[4] += 2;
We're talking semantics about whether or not this is iterating.
However, no pointers or iterators were used in this example.
There are no high level functions that add a scalar to a vector (array). You may be able to find a library that has those operations.
Some processors may have instructions that can add a scalar value to an array, but the C++ language doesn't have that facility.

Using std::reverse to reverse the order of the first few elements of a vector

If I have a
vector<int> vec { 1, 2, 3, 4}
How to use
std::reverse
to turn it into
vec {2, 1, 3, 4}
You can use reverse with iterators as arguments like this:
vector<int> vec { 1, 2, 3, 4};
reverse(vec.begin(), vec.begin()+2);
You may take a look here
You don't need to use std::reverse for what is essentially a much simpler operation. If you want to just swap the first two elements, use:
std::swap (vec[0], vec[1]);
If your desire is to swap elements in groups of two (leaving any odd one at the end alone), you can use something like:
for (int i = 0, lim = vec.size() - vec.size() % 2; i < lim; i += 2)
std::swap (vec[i], vec[i+1]);
If you want to reverse a section of the vector that's more than two elements, that's where I'd be contemplating the use of std::reverse. You could reverse sections of the vector vec containing {1, 2, 3, 4, 5} with calls like:
std::reverse (vec.begin(), vec.end() ); // -> {5, 4, 3, 2, 1}
std::reverse (vec.begin(), vec.begin() + 3); // -> {3, 2, 1, 4, 5}
std::reverse (vec.begin() + 1, vec.begin() + 4); // -> {1, 4, 3, 2, 5}

Using std::begin() and std::end() to construct vector from array

I am getting error, while trying to construct vector
int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 }; // source
std::vector<int> vv(data, data + 10); // ok
std::vector<int> vv(std::begin(data), std::end(data + 10)); // Error
GCC output:
main.cpp:59:61: error: no matching function for call to ‘end(int*)’
std::vector<int> vv(std::begin(data), std::end(data + 10));
Why I am getting this error ?
You're getting the error because of the + 10, which causes a decay from array of T to pointer to T. There's an std::end overload to take (a reference to) an array, but not one to take a pointer.
Just use: std::vector<int> vv(std::begin(data), std::end(data));
Alternatively, just use:
std::vector<int> vv{1, 2, 3, 4, 4, 3, 7, 8, 9, 10};
...and skip using the array at all.
Normally you use std::end on an array when you don't know the size. std::end is defined such that it will deduce the size and return a pointer to that offset:
std::vector<int> v(begin(data), end(data));

How to filter vector elements relative to other ones?

I a vector of vectors, each representing a a set (in the mathematical sense). For example:
{{1, 3}, {4, 9, 14}, {1, 3}, {1, 4, 8, 9, 10, 14, 16}, {1, 3, 9}, {4, 9, 17, 22}}
I want to make the most efficient C++ possible function capable of filtering (in place, if possible) the vector in order to remove every item that contains another.
For example, here:
{1, 3} is contained by {1, 3} and {1, 3, 9}
{4, 9, 14} is contained by {1, 4, 8, 9, 10, 14, 16}
The resulting vector would then be:
{{1, 3}, {4, 9, 14}, {4, 9, 17, 22}}
As I'm beginning with C++ don't really have any clue of how to do this efficiently. I found, on other answers here, the erase / remove idiom, which doesn't seem to be very appropriate here, except by passing erase a closure as predicate. Which doesn't seem really idiomatic in C++.
Please note that keeping the original ordering doesn't matter, nor does the ordering of values inside each set.
Given what I learnt so far, thanks to your very helpful comments, the solution I came up with is:
struct std::vector<size_t> colset;
bool less_colsets(const colset& a, const colset& b) {
return a.size() < b.size();
}
void sort_colsets(std::list<colset>& l) {
l.sort(less_colsets);
}
void strip_subsets(std::list<colset>& l) {
sort_colsets(l);
for (std::list<colset>::iterator i = l.begin(); i != l.end(); ++i) {
std::list<colset>::iterator j = next(i, 1);
while (j != l.end()) {
if (includes((*j).begin(), (*j).end(), (*i).begin(), (*i).end())) {
j = l.erase(j);
}
else {
++j;
}
}
}
}
Note that I replaced the outermost std::vector by std::list which is much more optimised for element removal anywhere.
This seems to work as expected, though I'd need some more tests to prove this. The next step will be to use a more efficient comparison function than includes, which would take into account the fact that each vector is lexically ordered (which the program guarantees). I'll try this tomorrow.
Edit: Looks like std::includes already takes care of this fact. YAY!
Thanks everybody.