c++ descending order with respect to second column - c++

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

Related

Getting all possible combinations of an integrer array in 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;
}

How to get the elements of a tuple

I am creating a scrabble game and i need to have a basic score to words on the dictionary.
I used make_tuple and stored it inside my tuple. Is there a way to access elements in a tuple as if it was in a vector?
#include <iostream>
#include <tuple>
#include <string>
#include <fstream>
void parseTextFile()
{
std::ifstream words_file("scrabble_words.txt"); //File containing the words in the dictionary (english) with words that do not exist
std::ofstream new_words_file("test.txt"); //File where only existing words will be saved
std::string word_input;
std::tuple<std::string, int> tupleList;
unsigned int check_integrity;
int counter = 0;
while(words_file >> word_input)
{
check_integrity = 0;
for (unsigned int i = 0; i < word_input.length(); i++)
{
if((int)word_input[i] >= 97 && (int)word_input[i] <= 123) //if the letter of the word belongs to the alphabet
{
check_integrity++;
}
}
if(word_input.length() == check_integrity)
{
new_words_file << word_input << std::endl; //add the word to the new file
tupleList = std::make_tuple(word_input, getScore(word_input)); //make tuple with the basic score and the word
counter++; //to check if the amount of words in the new file are correct
std::cout << std::get<0>(tupleList) << ": " << std::get<1>(tupleList) << std::endl;
}
}
std::cout << counter << std::endl;
}
One would generally use a tuple when there are more than two values of different types to store. For just two values a pair is a better choice.
In your case what you want to achieve seems to be a list of word-value pairs. You can store them in a container like a vector but you can also store them as key-value pairs in a map. As you can see when following the link, an std::map is literally a collection of std::pair object and tuples are a generalization of pairs.
For completeness, if my understanding of your code purpose is correct, these are additions to your code for storing each tuple in a vector - declarations,
std::tuple<std::string, int> correct_word = {};
std::vector<std::tuple<std::string, int>> existing_words = {};
changes in the loop that saves existing words - here you want to add each word-value tuple to the vector,
if(word_input.length() == check_integrity)
{
// ...
correct_word = std::make_tuple(word_input, getScore(word_input));
existing_words.push_back(correct_word);
// ...
}
..and finally example of usage outside the construction loop:
for (size_t iv=0; iv<existing_words.size(); ++iv)
{
correct_word = existing_words[iv];
std::cout << std::get<0>(correct_word) << ": " << std::get<1>(correct_word) << std::endl;
}
std::cout << counter << std::endl;
The same code with a map would look like:
The only declaration would be a map from strings to values (instead of a tuple and vector of tuples),
std::map<std::string, int> existing_words = {};
In the construction loop you would be creating the map pair in a single line like this,
if(word_input.length() == check_integrity)
{
// ...
existing_words[word_input] = getScore(word_input);
// ...
}
While after constructing you would be accessing map elements using .first for the word and .second for the counter. Below is a printing example that also uses a for auto loop:
for (const auto& correct_word : existing_words)
std::cout << correct_word.first << ": " << correct_word.second << std::endl;
std::cout << counter << std::endl;
Notice that maps are by default alphabetically ordered, you can provide your own ordering rules and also use an unordered map if you don't want any ordering/sorting.

Combinations of N Boost interval_set

I have a service which has outages in 4 different locations. I am modeling each location outages into a Boost ICL interval_set. I want to know when at least N locations have an active outage.
Therefore, following this answer, I have implemented a combination algorithm, so I can create combinations between elemenets via interval_set intersections.
Whehn this process is over, I should have a certain number of interval_set, each one of them defining the outages for N locations simultaneusly, and the final step will be joining them to get the desired full picture.
The problem is that I'm currently debugging the code, and when the time of printing each intersection arrives, the output text gets crazy (even when I'm using gdb to debug step by step), and I can't see them, resulting in a lot of CPU usage.
I guess that somehow I'm sending to output a larger portion of memory than I should, but I can't see where the problem is.
This is a SSCCE:
#include <boost/icl/interval_set.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
// Initializing data for test
std::vector<boost::icl::interval_set<unsigned int> > outagesPerLocation;
for(unsigned int j=0; j<4; j++){
boost::icl::interval_set<unsigned int> outages;
for(unsigned int i=0; i<5; i++){
outages += boost::icl::discrete_interval<unsigned int>::closed(
(i*10), ((i*10) + 5 - j));
}
std::cout << "[Location " << (j+1) << "] " << outages << std::endl;
outagesPerLocation.push_back(outages);
}
// So now we have a vector of interval_sets, one per location. We will combine
// them so we get an interval_set defined for those periods where at least
// 2 locations have an outage (N)
unsigned int simultaneusOutagesRequired = 2; // (N)
// Create a bool vector in order to filter permutations, and only get
// the sorted permutations (which equals the combinations)
std::vector<bool> auxVector(outagesPerLocation.size());
std::fill(auxVector.begin() + simultaneusOutagesRequired, auxVector.end(), true);
// Create a vector where combinations will be stored
std::vector<boost::icl::interval_set<unsigned int> > combinations;
// Get all the combinations of N elements
unsigned int numCombinations = 0;
do{
bool firstElementSet = false;
for(unsigned int i=0; i<auxVector.size(); i++){
if(!auxVector[i]){
if(!firstElementSet){
// First location, insert to combinations vector
combinations.push_back(outagesPerLocation[i]);
firstElementSet = true;
}
else{
// Intersect with the other locations
combinations[numCombinations] -= outagesPerLocation[i];
}
}
}
numCombinations++;
std::cout << "[-INTERSEC-] " << combinations[numCombinations] << std::endl; // The problem appears here
}
while(std::next_permutation(auxVector.begin(), auxVector.end()));
// Get the union of the intersections and see the results
boost::icl::interval_set<unsigned int> finalOutages;
for(std::vector<boost::icl::interval_set<unsigned int> >::iterator
it = combinations.begin(); it != combinations.end(); it++){
finalOutages += *it;
}
std::cout << finalOutages << std::endl;
return 0;
}
Any help?
As I surmised, there's a "highlevel" approach here.
Boost ICL containers are more than just containers of "glorified pairs of interval starting/end points". They are designed to implement just that business of combining, searching, in a generically optimized fashion.
So you don't have to.
If you let the library do what it's supposed to do:
using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval = DownTimes::interval_type;
using Records = std::vector<DownTimes>;
Using functional domain typedefs invites a higher level approach. Now, let's ask the hypothetical "business question":
What do we actually want to do with our records of per-location downtimes?
Well, we essentially want to
tally them for all discernable time slots and
filter those where tallies are at least 2
finally, we'd like to show the "merged" time slots that remain.
Ok, engineer: implement it!
Hmm. Tallying. How hard could it be?
❕ The key to elegant solutions is the choice of the right datastructure
using Tally = unsigned; // or: bit mask representing affected locations?
using DownMap = boost::icl::interval_map<TimePoint, Tally>;
Now it's just bulk insertion:
// We will do a tally of affected locations per time slot
DownMap tallied;
for (auto& location : records)
for (auto& incident : location)
tallied.add({incident, 1u});
Ok, let's filter. We just need the predicate that works on our DownMap, right
// define threshold where at least 2 locations have an outage
auto exceeds_threshold = [](DownMap::value_type const& slot) {
return slot.second >= 2;
};
Merge the time slots!
Actually. We just create another DownTimes set, right. Just, not per location this time.
The choice of data structure wins the day again:
// just printing the union of any criticals:
DownTimes merged;
for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
merged.insert(slot);
Report!
std::cout << "Criticals: " << merged << "\n";
Note that nowhere did we come close to manipulating array indices, overlapping or non-overlapping intervals, closed or open boundaries. Or, [eeeeek!] brute force permutations of collection elements.
We just stated our goals, and let the library do the work.
Full Demo
Live On Coliru
#include <boost/icl/interval_set.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/numeric.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include <iostream>
#include <vector>
using TimePoint = unsigned;
using DownTimes = boost::icl::interval_set<TimePoint>;
using Interval = DownTimes::interval_type;
using Records = std::vector<DownTimes>;
using Tally = unsigned; // or: bit mask representing affected locations?
using DownMap = boost::icl::interval_map<TimePoint, Tally>;
// Just for fun, removed the explicit loops from the generation too. Obviously,
// this is bit gratuitous :)
static DownTimes generate_downtime(int j) {
return boost::accumulate(
boost::irange(0, 5),
DownTimes{},
[j](DownTimes accum, int i) { return accum + Interval::closed((i*10), ((i*10) + 5 - j)); }
);
}
int main() {
// Initializing data for test
using namespace boost::adaptors;
auto const records = boost::copy_range<Records>(boost::irange(0,4) | transformed(generate_downtime));
for (auto location : records | indexed()) {
std::cout << "Location " << (location.index()+1) << " " << location.value() << std::endl;
}
// We will do a tally of affected locations per time slot
DownMap tallied;
for (auto& location : records)
for (auto& incident : location)
tallied.add({incident, 1u});
// We will combine them so we get an interval_set defined for those periods
// where at least 2 locations have an outage
auto exceeds_threshold = [](DownMap::value_type const& slot) {
return slot.second >= 2;
};
// just printing the union of any criticals:
DownTimes merged;
for (auto&& slot : tallied | filtered(exceeds_threshold) | map_keys)
merged.insert(slot);
std::cout << "Criticals: " << merged << "\n";
}
Which prints
Location 1 {[0,5][10,15][20,25][30,35][40,45]}
Location 2 {[0,4][10,14][20,24][30,34][40,44]}
Location 3 {[0,3][10,13][20,23][30,33][40,43]}
Location 4 {[0,2][10,12][20,22][30,32][40,42]}
Criticals: {[0,4][10,14][20,24][30,34][40,44]}
At the end of the permutation loop, you write:
numCombinations++;
std::cout << "[-INTERSEC-] " << combinations[numCombinations] << std::endl; // The problem appears here
My debugger tells me that on the first iteration numCombinations was 0 before the increment. But incrementing it made it out of range for the combinations container (since that is only a single element, so having index 0).
Did you mean to increment it after the use? Was there any particular reason not to use
std::cout << "[-INTERSEC-] " << combinations.back() << "\n";
or, for c++03
std::cout << "[-INTERSEC-] " << combinations[combinations.size()-1] << "\n";
or even just:
std::cout << "[-INTERSEC-] " << combinations.at(numCombinations) << "\n";
which would have thrown std::out_of_range?
On a side note, I think Boost ICL has vastly more efficient ways to get the answer you're after. Let me think about this for a moment. Will post another answer if I see it.
UPDATE: Posted the other answer show casing highlevel coding with Boost ICL

How to make lambda to extract all ids which belongs to year for example 1, 3, 5?

I have vector of pairs where first in pair is id and second is year of study
like
vector< pairs<uint64_t, int>> students;
How to make lambda to extract all ids which belongs to year for example 1, 3, 5 ?
I solved this through iteration but I wonder if I can in c++11 make this simpler.
You can use the algorithm std::copy_if to copy elements to another container, if they match a certain criteria.
using entry = std::pair<uint64_t, int>;
std::vector<entry> result;
std::copy_if(students.begin(), students.end(), std::back_inserter(result),
[](const entry& e) { return e.second == 1; });
I've included two approaches.
The first one uses for_each with a lambda which uses a regular if statement to find specific keys. copy_if is a good substitute if that's what you want to do with your findings. It has the same approach as for_each.
The second approach uses an unordered_map to enable associative (fast) lookup with keys.
With the information you gave it sounds like you should go with the map approach. Don't overcomplicate things.
#include <iostream>
#include <utility>
#include <vector>
#include <unordered_map>
using namespace std;
int main(int argc, char *argv[]) {
vector< pair<int, int>> v;
v.emplace_back(1,2);
v.emplace_back(3,4);
v.emplace_back(5,6);
for_each(v.begin(), v.end(),[](pair<int,int> p) {
cout << "checking key " << p.first << endl;
if (p.first == 1 || p.first == 5) { // look for key 1 and 5
cout << " found a key I was looking for: "
<< p.first << "," << p.second << endl;
}
});
unordered_map<int,int> m;
m.emplace(1,2);
m.insert(make_pair(3,4));
m.insert(make_pair(5,10));
cout << "value for key 5 is: " << m[5] << endl;
}

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).