I have 2 string tables and I would like to display the differences between the two tables.
Example :
Tab1 = "user1, user2, user3, user4"
Tab2 = "user3, user4, user2"
The difference in this case is that user 1 is missing.
I would like to know if there is a function that allows you to do this in the standard library or in Qt.
Thank you in advance.
What you need is std::set_difference which copies the elements from the sorted v1 which are not found in the sorted v2 to the diff. As mentioned, you should first sort your vectors and then search for difference.
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<std::string> v1 { "user1", "user2", "user3", "user4" };
std::vector<std::string> v2 { "user3", "user4", "user2" };
std::vector<std::string> diff;
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));
for (auto const& i : diff)
std::cout << i << std::endl;
}
If your string tables are stored as a string as you depicted, i.e,
Tab1 = "user1, user2, user3, user4"
Tab2 = "user3, user4, user2"
then you can use regular expression to first find out the users in Tab1 and store them in a set.
While searching for users in the Tab2, you can check if that user is already present in the set, if yes then remove that user from the set, if no then insert that user in the set.
Code:
#include <iostream>
#include <string>
#include <regex>
#include <set>
using namespace std;
ostream& operator<< (ostream& out, const set<string>& S)
{
for (const string& s : S)
out << s << endl;
return out;
}
int main()
{
string Tab1 = "user1, user2, user3, user4";
string Tab2 = "user3, user4, user2";
regex reg("user[0-9]{1,}");
set<string> S;
sregex_iterator pos1(Tab1.cbegin(), Tab1.cend(), reg);
sregex_iterator end1;
while (pos1 != end1)
{
S.insert(pos1->str());
++pos1;
}
sregex_iterator pos2(Tab2.cbegin(), Tab2.cend(), reg);
sregex_iterator end2;
while (pos2 != end2)
{
string temp = pos2->str();
if (S.find(temp) != S.cend())
S.erase(temp);
else
S.insert(temp);
++pos2;
}
cout << S << endl;
}
You can reduce computational complexity if you present you tables with std::set (or std::unordered_set). Then no need to sort tables (it's not cheap operation). I modify
NutCracker answer with usage of std::unordered_set:
#include <iostream>
#include <unordered_set>
#include <vector>
int main()
{
std::unordered_set<std::string> set1{ "user1", "user2", "user3", "user4" };
std::unordered_set<std::string> set2{ "user3", "user4", "user2", "user8" };
std::vector<std::string> diff;
for (const auto& s : set1)
{
auto it = set2.find(s);
if (it == set2.cend())
{
diff.emplace_back(s);
}
}
for (const auto& s : set2)
{
auto it = set1.find(s);
if (it == set1.cend())
{
diff.emplace_back(s);
}
}
for (const auto& s : diff)
std::cout << s.c_str() << std::endl;
}
Related
I have a Sorted vector of strings and whenever a new string is added we have a function which will allow us to calculate the new position. I should be able to use this position and update the vector.
Example:
Input Vector v1{Acr,Adr,Apr,Arr,Asr};
Input New String : Aar
As soon as the String uis Added the Vector Becomes
v1{Acr,Adr,Apr,Arr,Asr,Aar};
After Addition new position is computed with a Function that Will Return position to insert I1 in this case).
So after Some operation it should become v1{Aar,Acr,Adr,Apr,Arr,Asr};
So you want to insert into an std::vector?
How about using std::vector::insert then?
Example:
v1.insert(v1.begin() + index, new_value);
As #Jarod42 commented, you could use std::lower_bound to find the insertion position, like this: C++ std::lower_bound() function to find insertion point for an index-sorted vector.
Sounds like a combination of std::vector::insert and std::lower_bound should be a good match:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
using std::vector;
using std::string;
using std::lower_bound;
using std::cout;
vector<string> v1{"Acr","Adr","Apr","Arr","Asr"};
auto insertionPoint{lower_bound(begin(v1), end(v1), "Aar")};
v1.insert(insertionPoint, "Aar");
for (auto&&s:v1) cout << s << " ";
cout << "\n";
return 0;
}
Demo
The key element is: v1.insert(insertionPoint, "Aar"); to insert directly in the right place. If you don't want to use lower_bound because you already have the index (let's call it pos for the sake of this example), you can always do sth like this v1.insert(begin(v1)+pos, "Aar");
And if you really need to append at the end initially (for whatever reason) using std::sort sounds like the most natural solution. Although the most inefficient (given you can modify the vector anyway).
Expanding the answer with custom comparison function:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class Sth
{
std::string name_;
public:
explicit Sth(const std::string& s) : name_(s) {}
const std::string& name() const {return name_;}
};
int main(int, char*[])
{
using std::vector;
using std::string;
using std::lower_bound;
using std::cout;
vector<Sth> v1{Sth("Acr"),Sth("Adr"),Sth("Apr"),Sth("Arr"),Sth("Asr")};
auto insertionPoint{lower_bound(begin(v1), end(v1), Sth("Aar"),
[](auto&& lhs, auto&& rhs){return lhs.name() < rhs.name();})};
v1.insert(insertionPoint, Sth("Aar"));
for (auto&&s:v1) cout << s.name() << " ";
cout << "\n";
return 0;
}
Demo
If I have understood correctly you mean something like the following
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<std::string> v = { "Acr", "Adr", "Apr", "Arr", "Asr" };
v.push_back( "Aar" );
auto pos = std::upper_bound( std::begin( v ), std::prev( std::end( v ) ),
v.back() );
if ( pos != std::prev( std::end( v ) ) )
{
auto s = std::move( v.back() );
v.pop_back();
v.insert( pos, s );
}
for ( const auto &s : v )
{
std::cout << s << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
Aar Acr Adr Apr Arr Asr
I am trying to reorder the map in a descending way depending on the values, I have been trying to create a new map and insert the one which has the biggest value first but it keeps ordering the map by the keys.
I have also tried to reorder it by the value changing the form of the map into the other way but I will loose some data because I have more than one key which has the same value.
#include <iostream>
#include "SymbolFreq.h"
#include <string>
#include <fstream>
#include <streambuf>
#include <map>
using namespace std;
int main()
{
map <char, int> mymap;
map <char, int> realmap;
ifstream infile{ "ToCompress.txt" };
std::string str((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
std::map<char, int>::iterator itera;
for (auto it = str.begin(); it != str.end(); ++it)
{
itera = mymap.find(*it);
if (itera != mymap.end())
{
itera->second++;
}
else
{
mymap.insert({ *it, 1 });
}
}
int max = 0;
char provisionalChar;
int provisionalInt;
while (mymap.empty() == false)
{
for (auto it = mymap.cbegin(); it != mymap.cend(); ++it)
{
if (it->second > max)
{
max = it->second;
provisionalChar = it->first;
provisionalInt = it->second;
}
//cout << it->first << "\t" << it->second << "\n";
}
mymap.erase(provisionalChar);
realmap.insert({ provisionalChar, provisionalInt });
max = 0;
}
for (auto it = realmap.cbegin(); it != realmap.cend(); ++it)
{
cout << it->first << "\t" << it->second << "\n";
}
return 0;
}
If I understand the question properly, you'd like to count how many times each char appears in the file and then produce a map sorted with the char that appeared most time first.
Here's one idea:
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <unordered_map>
int main() {
std::ifstream infile{"ToCompress.txt"};
// "mymap" is only used for counting how many times each char appears.
std::unordered_map<char, std::uintmax_t> mymap;
// Loop directly over the file. No vector needed:
std::for_each(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), [&mymap](char ch) {
// No need to find first - operator[] inserts an element
// for the key ("ch") if it's missing.
++mymap[ch];
});
// Transform the unordered_map into a multimap where the count is the key
// and in which we use a descending sort order (std::greater):
std::multimap<std::uintmax_t, char, std::greater<std::uintmax_t>> realmap;
std::transform(mymap.begin(), mymap.end(),
std::inserter(realmap, realmap.end()),
[](const auto& ch_co) -> std::pair<std::uintmax_t, char> {
// return a pair with key and value swapped
return {ch_co.second, ch_co.first};
});
// Print the result
for(auto& [count, ch] : realmap) {
std::cout << count << '\t' << ch << '\n';
}
}
Possible output:
537479
120204 t
113285 e
80681
80670 i
79862 n
77984 r
77464 s
69994 o
67377 a
...
Apparently, <space>, t, e and \n are tne most common characters in my C++ programs (which is what I used as input)
Your question may be ill-posed; take a step back and state what you are really trying to accomplish.
That said, I'll attempt an answer based on what you've written.
It looks like you're trying to sort an std::map by value, in which case your question is a duplicate of either this or this question.
Regarding your initial attempt:
Take a look at this table. Only sequence containers allow you to directly influence order. As with priority queue you have limited control over the order of associative containers and almost zero control for unordered containers.
So I need help finding the last name with the most first names. I then need to print out the first names. I have gotten it to print out all of the names from every last name, but I can't figure out how to only print the one with most first name.
#include <stdio.h>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
typedef set <string> fnset;
main()
{
map <string, fnset *> lnames;
map <string, fnset *>::iterator lnit;
fnset *fnames;
fnset::iterator fnit;
string fn, ln;
while (cin >> fn >> ln) {
lnit = lnames.find(ln);
if (lnit == lnames.end()) {
fnames = new fnset;
lnames.insert(make_pair(ln, fnames));
} else {
fnames = lnit->second;
}
fnames->insert(fn);
}
for (lnit = lnames.begin(); lnit != lnames.end(); lnit++) {
fnames = lnit->second;
for (fnit = fnames->begin(); fnit != fnames->end(); fnit++) {
cout << *fnit << endl;
}
}
}
You can call std::max_element from <algorithm> library. One of its overload has the following form.
ForwardIt max_element( ForwardIt first, ForwardIt last, Compare comp );
first and last and iterators to the container, and comp is the comparision function object used to compare two elements. For more info, check cppreference page, http://en.cppreference.com/w/cpp/algorithm/max_element.
#include <algorithm>
auto largest = std::max_element(
lnames.begin(), lnames.end(), [](auto const& p1, auto const& p2) {
return p1.second->size() < p2.second->size();
});
for (auto const& name : *largest->second)
std::cout << name << '\t';
I'd strongly suggest using a multimap<string, string> lnames here. You could populate it like this:
for(string fn, ln; cin >> fn >> ln;) {
lnames.insert(make_pair(ln, fn));
}
Then just use iterators with multimap::upper_bound to find the largest:
auto max_start = cbegin(lnames);
auto max_end = cbegin(lnames);
size_t max_distance = 0U;
for(auto it_start = cbegin(lnames), it_finish = cbegin(lnames); it_start != cend(lnames); it_start = it_finish) {
it_finish = lnames.upper_bound(it_finish->first);
auto it_distance = distance(it_start, it_finish);
if(it_distance > max_distance) {
max_distance = it_distance;
max_start = it_start;
max_finish = it_finish;
}
}
And finally to output this simply use ostream_iterators:
copy(max_start, max_finish, ostream_iterator<string>(cout, " "))
Finding an element in a vector of structures
this link showed me, how to look for a value inside a structure.
but i have something like this,
struct sample {
string name;
vector<string> values;
};
vector<sample>v1;
and this is a vector of structures. how to search for a particular string in the values vector, that is present inside the structure samples ? which itself, is a vector of structures ?
thanks.
You can iterate through the vector v1 containing sample structures accessing each vector v1 member as a struct. Then, you can access the struct member vector to search for desired string:
for (const sample &it : v1) {
for (const string &st : it.values) {
if (st == ...) {
}
}
}
You can use a combination of std::find_if and std::find.
The std::find_if goes through the sample objects and checks every element with a predicate which itself uses std::find to go through all std::string elements inside and compares each of them to the token you want to find.
Here is an example, using a lambda function to create the predicate:
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
struct sample
{
std::string name;
std::vector<std::string> values;
};
int main()
{
std::vector<sample> const v1 =
{
{ "one", { "a", "b" } },
{ "two", { "c", "token to find", "d", "e" } },
{ "three", { "f"} }
};
using std::begin;
using std::end;
auto const token = "token to find";
// go through all samples
auto const sample_iter = std::find_if(begin(v1), end(v1), [&token](sample const& s)
{
// in each sample, go through all values
auto const string_iter = std::find(begin(s.values), end(s.values), token);
return string_iter != end(s.values);
});
if (sample_iter == end(v1))
{
std::cout << "not found\n";
}
else
{
std::cout << sample_iter->name << '\n';
}
}
Output:
two
I have a folder that havs files with these kind of names "In_YMD_xxx" and "Out_YMD_xxx" where YMD is year, month and day (exp. 20150101) and xxx is its idx such as 050. I am looking for a simple way to read the name of latest files (In_.. and Out_..) that were created using boost library in C++.
Here is an example of files that I have on my directory: "C:\Customer\AppleFruit\"
In_20141101_001
In_20150102_002
In_20150130_0101
In_20150201_001
Out_20140501_101
Out_20141101_101
Out_20150101_152
Out_20150201_191
Below is the code that i am trying to write in C++:
#include "boost/filesystem.hpp"
boost::filesystem::path p( "C:\Customer\AppleFruit\");
typedef vector<path> vec; //sort path
vec inVec, outVec;
std::string inFilename, outFileName;
sort(v.begin(), v.end());
for (vec::const_iterator it (v.begin()); it != v.end(); ++it)
{
if ( file_name_Starts_with_IN ) // here I am looking for the correct "if condition"
inVec.push_back( *it);
else if ( file_name_Starts_with_OUT ) //same thing here
outVec.push_back( *it);
}
inFilename = inVec(end);
outFileName= outVec(end);
Any idea please..Thanks
Updated after the comment.
If you want a more than two way partition, I'd suggest making it table-driven:
Live On Coliru
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>
#include <iostream>
#include <map>
int main() {
using boost::filesystem::path;
using boost::filesystem::directory_iterator;
using boost::make_iterator_range;
path p("."); // or "C:\\Customer\\AppleFruit\\"
std::map<std::string, std::vector<path> > bins {
{ "In_", {} },
{ "Out_", {} },
//{ "", {} }, // remaining files
};
for(auto&& de: make_iterator_range(directory_iterator("."), {}))
for(auto& bin: bins)
if (de.path().filename().native().find(bin.first) == 0)
bin.second.push_back(std::move(de));
for(auto& bin: bins)
for(auto& f : boost::sort(bin.second))
std::cout << "Prefix '" << bin.first << "': " << f << "\n";
}
_Old answer: _
You can use partition_copy with a suitable predicate (here, I used a lambda):
Live On Coliru
#include "boost/filesystem.hpp"
#include <vector>
#include <iostream>
int main() {
boost::filesystem::path p("."); // or "C:\\Customer\\AppleFruit\\"
std::vector<boost::filesystem::path> inVec, outVec;
std::partition_copy(
boost::filesystem::directory_iterator(p), {},
back_inserter(inVec),
back_inserter(outVec),
[](boost::filesystem::directory_entry const& de) {
return de.path().filename().native().find("In_") == 0;
; });
std::sort(inVec.begin(), inVec.end());
std::sort(outVec.begin(), outVec.end());
for(auto& f : inVec)
{
std::cout << f << "\n";
}
}
Lists all file names that start with "In_" (case sensitively). On Coliru, from files created with
touch {In,Out}_{a..m}_file.txt
this means that only
"./In_a_file.txt"
"./In_b_file.txt"
"./In_c_file.txt"
"./In_d_file.txt"
"./In_e_file.txt"
"./In_f_file.txt"
"./In_g_file.txt"
"./In_h_file.txt"
"./In_i_file.txt"
"./In_j_file.txt"
"./In_k_file.txt"
"./In_l_file.txt"
"./In_m_file.txt"
are matched and printed, in sorted order