Getting all possible combinations of an integrer array in C++ - c++

I have an array of integers, for example: a[1,2,3]. I would like to get all possible combinations of these numbers where they don't repeat, possibly with recursion.
I saw something like this done with strings here: Get all combinations without duplicates but don't know how to adapt it to integers without using any standard algorithms.
So I would like something like this as an output: {1},{2},{3},{1,2},{2,3},{1,3},{1,2,3}
Thanks in advance!

You can achieve all permutations of a list with comparable elements using std::next_permutation from <algorithms> library.
The cppreference has a nice article about this: https://en.cppreference.com/w/cpp/algorithm/next_permutation
We can use the code example to apply to your question.
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
void print_vector(const std::vector<int>& array) {
for (const int item : array)
{
std::cout << item << " ";
}
std::cout << std::endl;
}
int main()
{
std::vector<int> a({ 5,1,8,7,2 });
std::sort(a.begin(), a.end());
do {
print_vector(a);
} while(std::next_permutation(a.begin(), a.end()));
}

You can use std::next_permuation to achieve your goal.
Keep in mind you need to sort the array before starting to use this algorithm.
The loop will exit the first time std::next_permuation returns false.
If the array isn't sorted by the time you start std::next_permuation loop, you will miss all the arrays that are lexicographically lower than the current one when entering the loop.
int main()
{
std::vector<int> a = { 5,1,8,7,2 };
std::sort(a.begin(), a.end());
std::cout << "Possible permutations :\n";
do {
for (auto o : a)
std::cout << o;
std::cout << std::endl;
} while (std::next_permutation(a.begin(), a.end()));
return 0;
}

Related

accessing elements of dynamic array of lists

So, I don't know how can I print elements of such a list.
list<int>* a;
a = new list<int>(4);
a[0].push_back(1);
a[0].push_back(3);
a[2].push_back(5);
a[2].push_back(7);
cout << a[0].front() << '\n';
cout << a[1].back() << '\n';
Firstly, I tried to print it via range-based for loop, but it didn't work either.
for(auto element: a[0]) cout << element << '\n'; // doesn't work
Are you trying to store a list of integer lists? Because this implementation will not work since you only have a list of integers and no push_back() operation is available for the elements.
Remove the index operator for all those push_back() operations and take out the index operator for the front() and back() as those are not available to the elements either.
I would use a std::vector instead of new (which should technically be new[] in this case anyway).
#include <iostream>
#include <list>
#include <vector>
int main() {
std::vector<std::list<int>> a(4);
a[0].push_back(1);
a[0].push_back(3);
a[2].push_back(5);
a[2].push_back(7);
for (std::list<int> const& l : a) {
for (int i : l) {
std::cout << i << ' ';
}
std::cout << '\n';
}
}
Output
1 3
5 7

Unexpected behavior using `std::count` on `std::vector` of pairs

My goal is to completely remove all elements in a std::vector<std::pair<int, int>> that occur more than once.
The idea was to utilize std::remove with std::count as part of the predicate. My approach looks something like this:
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using i_pair = std::pair<int, int>;
int main()
{
std::vector<i_pair> vec;
vec.push_back(i_pair(0,0)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
vec.push_back(i_pair(1,1)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
auto predicate = [&](i_pair& p)
{
return std::count(vec.begin(), vec.end(), p) > 1;
};
auto it = std::remove_if(vec.begin(), vec.end(), predicate);
cout << "Reordered vector:" << endl;
for(auto& e : vec)
{
cout << e.first << " " << e.second << endl;;
}
cout << endl;
cout << "Number of elements that would be erased: " << (vec.end() - it) << endl;
return 0;
}
The array gets reordered with both of the (0,1) elements pushed to the end, however the iterator returned by std::remove points at the last element. This means that a subsequent erase operation would only get rid of one (0,1) element.
Why is this behavior occurring and how can I delete all elements that occur more than once?
Your biggest problem is std::remove_if gives very little guarantees about the contents of the vector while it is running.
It guarantees at the end, begin() to returned iterator contains elements not removed, and from there until end() there are some other elements.
Meanwhile, you are iterating over the container in the middle of this operation.
It is more likely that std::partition would work, as it guarantees (when done) that the elements you are "removing" are actually stored at the end.
An even safer one would be to make a std::unordered_map<std::pair<int,int>, std::size_t> and count in one pass, then in a second pass remove everything whose count is at least 2. This is also O(n) instead of your algorithms O(n^2) so should be faster.
std::unordered_map<i_pair,std::size_t, pair_hasher> counts;
counts.reserve(vec.size()); // no more than this
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));
you have to write your own pair_hasher. If you are willing to accept nlgn performance, you could do
std::map<i_pair,std::size_t> counts;
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));

Looping through std::vector to find matches from std::string array, easier way?

I am looping through std::vector and std::string array to find matches from the vector.
Example:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::cout << "Searching...\n";
std::vector<std::string> myVector;
myVector.push_back("Word");
myVector.push_back("Word2");
myVector.push_back("Word4");
myVector.push_back("Word6");
myVector.push_back("Word7");
std::string myStringArr[] =
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
for (auto Vec : myVector)
{
for(auto Str : myStringArr)
{
if(Vec == Str)
{
std::cout << "Found: " << Vec << std::endl;
}
}
}
std::cin.ignore(2);
return 0;
}
This works fine. But I am coming from C language(trying to get into C++ 11), and not sure if this is the best solution.
Platform is windows, and I do not (currently) use any external libraries like boost, as you can see from the code.
Is there a better / cleaner way to achieve the same result?
Your solution works fine and is good as long as the vector and the string array are not too long.
Little improvement on the code: don't use auto for simple types, it's just less readable (you could use const string& instead).
You could do something more efficient: Your algorithm complexity is O(NxM) with N and M the sizes of the vector and array.
Storing the values of the vector in a hash_set and then checking if they are in the array would be O(N+M).
If your array and vector are sorted, you can use std::set_intersection.
According to cplusplus.com, the complexity is Up to linear in 2*(count1+count2)-1 (where countX is the distance between firstX and lastX): Compares and assigns elements.
If they are not, you can sort them first, which only take O(nlog(n) + mlog(m)) (with n being the number of elements in the vector, and m in the array (or vice versa)) time, before linear for the range (this is better than your O(n*m) solution).
Here how it looks like :
#include <iostream> // std::cout
#include <algorithm> // std::set_intersection, std::sort
#include <vector> // std::vector
std::vector<std::string> intersection(myVector.size()); //needs to be allocated
std::sort (myVector.begin(),myVector.end());
std::sort (myStringArr,myStringArr+10);
auto it = std::set_intersection (myVector.begin(), myVector.end(), //first range
myStringArr, myStringArr+10, // second range
intersection.begin()); // the result range
v.resize(it-v.begin());
std::cout << "The intersection has " << (v.size()) << " elements:\n";
Yes, you can use std::find_first_of for this:
auto itVec = myVector.begin();
for (;;) {
itVec = std::find_first_of(itVec, myVector.end(), std::begin(myStringArr), std::end(myStringArr);
if (itVec == myVector.end())
break;
std::cout << "Found: " << *itVec << '\n';
++itVec;
}
Use std::find_first_of:
for (auto str : myStringArr)
{
if (std::find_first_of(str, std::begin(myVector). std::end(myVector))
{
std::cout << "Found: " << str << std::endl;
}
}
You can use std::set to store your strings:
std::set<std::string> myStringSet
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
for (auto Vec : myVector)
{
if( myStringSet.count( Vec ) )
{
std::cout << "Found: " << Vec << std::endl;
}
}
}
Another solution is to sort your vector and use std::binary_search:
std::vector<std::string> myStringArr
{
"Word",
"Word1",
"Word2",
"Word3",
"Word4",
"Word5",
"Word6",
"Word7"
};
std::sort( myStringArr.begin(), myStringArr.end() );
for (auto Vec : myVector)
{
if( std::binary_search( myStringArr.begin(), myStringArr.end(), Vec ) {
std::cout << "Found: " << Vec << std::endl;
}
}
The std::set_intersection algorithm does what you want.
Sort your two data structures using std::sort (or use sorted data structures instead) :
std::sort(myVector.begin(), myVector.end());
std::sort(myStringArr, myStringArr + 8);
And then use std::set_intersection :
std::set_intersection(
myVector.begin(), myVector.end(),
myStringArr, myStringArr + 8,
std::ostream_iterator<std::string>(std::cout, "\n"));
Note the use of std::ostream_iterator for printing the result on std::cout.
Since, in general case, both vector and array are not sorted, you have to iterate over every element. Therefore that is the best way.
Only one small thing. for (auto Vec : myVector) is going to make a copy of each element. Since std::string makes shallow copy, you will not notice. But in some other case, it may be noticable. Better way would be to use a reference :
for (const auto& Vec : myVector)

c++ descending order with respect to second column

Text file where the data is as follows:
0 320.77
1 100.44
2 117.66
3 541.55
The data is sorted with respect to the first column but I want to sort it with respect to the second column and in descending order.
The output should be as follows:
3 541.55
0 320.77
2 117.66
1 100.44
I had a similar problem to sorting a file by the second data type, i would give code but this seems to be a homework problem, so here is an explanation of how i solved it:
read the line into a string
iterate to the second number by skipping to the next space
grab the second number from the string and place it in a separate string, then atoi() the string to get an integer
sort the string using the integer in a sort function then call the function in std::sort of qsort()
I think that would not hurt #laky college performance now if I entertain myself a bit and provide an answer.
#include <utility>
#include <sstream>
#include <vector>
#include <iostream>
#include <algorithm>
using Entry = std::pair<int, float>;
using Storage = std::vector<Entry>;
void dump(const Storage& storage)
{
for(auto& [i, v] : storage)
std::cout << i << " " << v << "\n";
}
int main(void)
{
std::stringstream input;
input.str("0 320.77\n1 100.44\n2 117.66\n3 541.55\n");
Storage storage;
for ( /* read 'file' into vector storage for processing */
Entry entry;
input >> entry.first >> entry.second && input.good();
)
{
storage.push_back(std::move(entry));
}
std::cout << "Original data:\n";
dump(storage);
std::sort(storage.begin(), storage.end(),
[](Entry l, Entry r) /* sorting predicate */
{
return l.second > r.second;
});
std::cout << "Sorted data:\n";
dump(storage);
return 0;
}
on GodBolt

Does g++'s std::list::sort invalidate iterators?

According to SGI, cplusplus.com, and every other source I've got, the sort() member function of the std::list should not invalidate iterators. However, that doesn't seem to be the case when I run this code (c++11):
#include <list>
#include <chrono>
#include <random>
#include <iostream>
#include "print.hpp"
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<unsigned int> distribution(1, 1000000000);
auto rng = std::bind(distribution, generator);
// C++11 RNG stuff. Basically, rng() now gives some unsigned int [1, 1000000000]
int main() {
unsigned int values(0);
std::cin >> values; // Determine the size of the list
std::list<unsigned int> c;
for (unsigned int n(0); n < values; ++n) {
c.push_front(rng());
}
auto c0(c);
auto it(c.begin()), it0(c0.begin());
for (unsigned int n(0); n < 7; ++n) {
++it; // Offset these iterators so I can print 7 values
++it0;
}
std::cout << "With seed: " << seed << "\n";
std::cout << "Unsorted list: \n";
print(c.begin(), c.end()) << "\n";
print(c.begin(), it) << "\n\n";
auto t0 = std::chrono::steady_clock::now();
c0.sort();
auto d0 = std::chrono::steady_clock::now() - t0;
std::cout << "Sorted list: \n";
print(c0.begin(), c0.end()) << "\n";
print(c0.begin(), it0) << "\n"; // My own print function, given further below
std::cout << "Seconds: " << std::chrono::duration<double>(d0).count() << std::endl;
return 0;
}
In print.hpp:
#include <iostream>
template<class InputIterator>
std::ostream& print(InputIterator begin, const InputIterator& end,
std::ostream& out = std::cout) {
bool first(true);
out << "{";
for (; begin != end; ++begin) {
if (first) {
out << (*begin);
first = false;
} else {
out << ", " << (*begin);
}
}
out << "}";
return out;
}
Sample input/output:
11
With seed: 3454921017
Unsorted list:
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868, 249266563, 224065083, 843444019, 523600743}
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868}
Sorted list:
{8707580, 224065083, 249266563, 317964049, 319409064, 523600743, 625860546, 672762972, 756270868, 762505303, 843444019}
{8707580, 224065083}
Seconds: 2.7e-05
Everything works as expected, except for the printing. It is supposed to show 7 elements, but instead the actual number is fairly haphazard, provided "value" is set to more than 7. Sometimes it gives none, sometimes it gives 1, sometimes 10, sometimes 7, etc.
So, is there something observably wrong with my code, or does this indicate that g++'s std::list (and std::forward_list) is not standards conforming?
Thanks in advance!
The iterators remain valid and still refer to the same elements of the list, which have been re-ordered.
So I don't think your code does what you think it does. It prints the list from the beginning, to wherever the 7th element ended up after the list was sorted. The number of elements it prints therefore depends on the values in the list, of course.
Consider the following code:
#include <list>
#include <iostream>
int main() {
std::list<int> l;
l.push_back(1);
l.push_back(0);
std::cout << (void*)(&*l.begin()) << "\n";
l.sort();
std::cout << (void*)(&*l.begin()) << "\n";
}
The two address printed differ, showing that (unlike std::sort), std::list::sort has sorted by changing the links between the elements, not by assigning new values to the elements.
I've always assumed that this is mandated (likewise for reverse()). I can't actually find explicit text to say so, but if you look at the description of merge, and consider that the reason for list::sort to exist is presumably because mergesort works nicely with lists, then I think it's "obviously" intended. merge says, "Pointers and references to the moved elements of x now refer to those same elements but as members of *this" (23.3.5.5./23), and the start of the section that includes merge and sort says, "Since lists allow fast insertion and erasing from the middle of a list, certain operations are provided specifically for them" (23.3.5.5/1).