remove_if from vector of strings - algorithm

I need to remove some elements from a vector of strings if any of the strings contain a certain word.
How can I write the unary predicate for remove_if?
Here is code sample:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool remove_if_found(string word)
{
// ???
}
int main()
{
vector<string> data {
{ "the guitar has six strings" },
{ "the violin has four strings" },
{ "the the violin is more difficult to learn" },
{ "saxophones are a family of instruments" },
{ "the drum is a set of percussions" },
{ "the trumpet is a brass" }
};
cout << data.size() << endl; // output: 6
remove_if(data.begin(), data.end(), remove_if_found("violin")); // error
cout << data.size() << endl; // output should be: 4
return 0;
}

The problem is that the expression remove_if_found("violin") returns a bool which cannot be passed to std::remove_if.
The easiest solution for you would be to change remove_if_found as such:
void remove_if_found(vector<string>& vec, const string& word)
{
vec.erase(remove_if(vec.begin(), vec.end(), [&word](const string& el) {
// check if the word is contained within the string
return el.find(word) != std::string::npos;
}), vec.end());
}
which takes a reference to the vector as well as the string to look for and does the removal as normal.
Then in main you just call it as such:
remove_if_found(data, "violin");
The reason for the erase+remove usage in the remove_if_function is important. std::remove_if merely moves the elements you wish to remove to the end of the vector and returns an iterator to the first of those (re)moved elements. On the other hand std::vector::erase takes two iterators - the returned one from std::remove_if iterator and vec.end() and actually erases them from the vector.

Related

Error using Max_Element with String Vector

I'm implementing an algorithm to return a vector string array with only the largest elements in the vector string array of entrance:
vector<string> solution(vector<string> inputArray) {
vector<string> s;
auto m = *max_element(inputArray.begin(),inputArray.end());
for(int i=0;i<inputArray.size();i++){
if(inputArray[i].size() == m.size())
{
s.push_back(inputArray[i]);
}
}
return s;
It works for every test case except in the case the entry string vector is {"enyky", "benyky","yely","varennyky"}. 'm' should return a pointer to "varennyky", but it returns a pointer to "yely" instead.
I digged in to the documentation for max_element, but cant find what I'm doing wrong. Can anybody help me?
Your function is comparing the strings lexicographically, which is the default comparison in case of strings.
To illustrate, consider the following example:
#include <algorithm>
#include <string>
#include <vector>
// Print a vector of strings
void print_vec(std::vector<std::string> vec)
{
for (const auto& el : vec) {
std::cout << el << " ";
}
std::cout << std::endl;
}
// Compares strings by length
bool less_length(const std::string& s1, const std::string& s2)
{
return s1.length() < s2.length();
}
int main()
{
std::vector<std::string> test_0 = {"enyky", "benyky","yely","varennyky"};
// Default sort and max element
std::sort(test_0.begin(), test_0.end());
print_vec(test_0);
const auto largest_0 = *std::max_element(test_0.begin(), test_0.end());
std::cout << "Largest member (lexicographically): " << largest_0 << '\n' << std::endl;
// Sort and max element by string size
std::sort(test_0.begin(), test_0.end(), less_length);
print_vec(test_0);
const auto largest_1 = *std::max_element(test_0.begin(), test_0.end(), less_length);
std::cout << "Largest member (by string length): " << largest_1 << std::endl;
}
The first part of the program runs what you are doing in your function: it finds the maximum element based on lexicographic ordering. According to that ordering, the largest string is yely, you can see that by the output from sort.
The second part uses a custom comparison function, borrowed directly from this book. It uses string length to determine the order in the max_element call and the result is what you were looking for. Again, the sorted vector is also printed for clarity.

How do i assign values to my fraction objecct using make_unique()?

#include <memory> // for std::unique_ptr and std::make_unique
#include <iostream>
class Fraction
{
private:
int m_numerator;
int m_denominator;
public:
Fraction(int numerator, int denominator) :
m_numerator{ numerator }, m_denominator{ denominator }
{
}
friend std::ostream& operator<<(std::ostream& out, const Fraction &f1)
{
out << f1.m_numerator << "/" << f1.m_denominator;
return out;
}
friend operator=(const Fraction &f1,const int numerator,const int denominator){
f1.m_numerator=numerator;
f1.m_denominator=denominator;
}
};
int main()
{
// Create a single dynamically allocated Fraction with numerator 3 and denominator 5
std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
std::cout << *f1 << '\n';
// Create a dynamically allocated array of Fractions of length 4
// We can also use automatic type deduction to good effect here
auto f2{ std::make_unique<Fraction[]>(4) };
f2[0]=(3,5);
f2[1]=(67,82,5,543345);
std::cout << f2[0] << '\n';
std::cout << f2[1] << '\n';
return 0;
}
First, operator= can be implemented only as member function, not free function. So your approach is just wrong. Second, overloaded operator= can accept only one parameter. The closest thing you want, can be achived by passing initializer_list as this parameter:
Fraction& operator=(std::initializer_list<int> il){
// some code validating size of il here
this->m_numerator=*il.begin();
this->m_denominator = *(il.begin()+1);
return *this;
}
the use looks like:
f2[0]={3,5};
f2[1]={67,84};
Full demo

Conversion of data type using auto in C++

I have 2 vector container which contains 2 different kind of value with data type uint32_t. I want to print both of them together.
Like this is what I have
vector<uint32_t> data1;
vector<uint32_t> data2;
Now I know a method for single data like below
for(auto const& d1: data1)
cout<< d1 << endl;
But I want to print both data together like this,
cout<< d1 << "\t" << d2 << endl;
How can I do this using auto? (where d2 is auto converted value from data2)
You could use a normal for loop over the index:
for (auto i = 0u; i != n; ++i)
std::cout << data1[i] << "\t" << data2[i] << "\n";
Edit: if you want to convert the uint32_t to an int, for example, you could do:
auto d1 = static_cast<int>(data1[i]);
but it is up to you to ensure the conversion is safe. i.e the value fits in the target type.
Use the Boost Zip Iterator, which will let you have a range of pairs rather than two ranges of the vectors' data types. Something along the lines of:
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range.hpp>
#include <stdint.h>
#include <vector>
#include <iostream>
template <typename... TContainer>
auto zip(TContainer&... containers) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(containers)...))>> {
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(containers)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(containers)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
int main()
{
std::vector<uint32_t> data1( { 11, 22, 33 } );
std::vector<uint32_t> data2( { 44, 55, 66 } );
for (auto t : zip(data1, data2)) {
std::cout << boost::get<0>(t) << "\t" << boost::get<1>(t) << "\n";
}
}
The zip() function is due to this question and you can put it in a separate header file since it's not specific to your case.
If possible (and plausible for your use case): work with a container of pairs
If your application is not in a bind w.r.t. computer resources, and you know that you will be working with the values of your two containers as pairs (assuming same-length containers, as in your example), it might be useful to actually work with a container of pairs, which also ease the use of the neat range-based for loops ( >= C++11).
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<uint32_t> data1 = {1, 2, 3};
std::vector<uint32_t> data2 = {4, 5, 6};
// construct container of (int, int) pairs
std::vector<std::pair<int, int>> data;
data.reserve(data1.size());
std::transform(data1.begin(), data1.end(), data2.begin(), std::back_inserter(data),
[](uint32_t first, uint32_t second) {
return std::make_pair(static_cast<int>(first), static_cast<int>(second));
}); /* as noted in accepted answer: you're responsible for
ensuring that the conversion here is safe */
// easily use range-based for loops to traverse of the
// pairs of your container
for(const auto& pair: data) {
std::cout << pair.first << " " << pair.second << "\n";
} /* 1 4
2 5
3 6 */
return 0;
}

Can I move the contents of one vector to the end of another?

I want to do something like the following (a and b are both vector<my_moveable_type>):
a.insert(a.end(), b.begin(), b.end());
But I want the operation to move b's elements into a instead of copying them. I have found std::vector::emplace but that is just for a single element, not a range.
Can this be done?
You can use std::make_move_iterator, so that accesses to the iterator returns rvalue references instead of lvalue references:
a.insert(a.end(), std::make_move_iterator(b.begin()), std::make_move_iterator(b.end()));
There is a std::move algorithm that appears to do what you want. In the following code the source std::vector is left with empty strings (the vector size doesn't change).
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> one{"cat", "dog", "newt"};
std::vector<std::string> two;
std::move(begin(one), end(one), back_inserter(two));
std::cout << "one:\n";
for (auto& str : one) {
std::cout << str << '\n';
}
std::cout << "two:\n";
for (auto& str : two) {
std::cout << str << '\n';
}
}
Working code at ideone.com

Implementing equivalence relations in C++ (using boost::disjoint_sets)

Assume you have many elements, and you need to keep track of the equivalence relations between them. If element A is equivalent to element B, it is equivalent to all the other elements B is equivalent to.
I am looking for an efficient data structure to encode this information. It should be possible to dynamically add new elements through an equivalence with an existing element, and from that information it should be possible to efficiently compute all the elements the new element is equivalent to.
For example, consider the following equivalence sets of the elements [0,1,2,3,4]:
0 = 1 = 2
3 = 4
where the equality sign denotes equivalence. Now we add a new element 5
0 = 1 = 2
3 = 4
5
and enforcing the equivalence 5=3, the data structure becomes
0 = 1 = 2
3 = 4 = 5
From this, one should be able to iterate efficiently through the equivalence set for any element. For 5, this set would be [3,4,5].
Boost already provides a convenient data structure called disjoint_sets that seems to meet most of my requirements. Consider this simple program that illustates how to implement the above example:
#include <cstdio>
#include <vector>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/unordered/unordered_set.hpp>
/*
Equivalence relations
0 = 1 = 2
3 = 4
*/
int main(int , char* [])
{
typedef std::vector<int> VecInt;
typedef boost::unordered_set<int> SetInt;
VecInt rank (100);
VecInt parent (100);
boost::disjoint_sets<int*,int*> ds(&rank[0], &parent[0]);
SetInt elements;
for (int i=0; i<5; ++i) {
ds.make_set(i);
elements.insert(i);
}
ds.union_set(0,1);
ds.union_set(1,2);
ds.union_set(3,4);
printf("Number of sets:\n\t%d\n", (int)ds.count_sets(elements.begin(), elements.end()));
// normalize set so that parent is always the smallest number
ds.normalize_sets(elements.begin(), elements.end());
for (SetInt::const_iterator i = elements.begin(); i != elements.end(); ++i) {
printf("%d %d\n", *i, ds.find_set(*i));
}
return 0;
}
As seen above one can efficiently add elements, and dynamically expand the disjoint sets. How can one efficiently iterate over the elements of a single disjoint set, without having to iterate over all the elements?
Most probably you can't do that, disjoint_sets doesn't support iteration over one set only. The underlying data structure and algorithms wouldn't be able to do it efficiently anyway, i.e. even if there was support built in to disjoint_sets for iteration over one set only, that would be just as slow as iterating over all sets, and filtering out wrong sets.
Either I am missing something, you forgot to mention something, or maybe you were overthinking this ;)
Happily, equivalence is not equality. For A & B to be equivalent; they only need to share an attribute with the same value. this could be a scalar or even a vector. Anyway, I think your posted requirements can be achieved just using std::multiset and it's std::multiset::equal_range() member function.
//////////////////////////////////////
class E
{
//could be a GUID or something instead but the time complexity of
//std::multiset::equal_range with a simple int comparison should be logarithmic
static size_t _faucet;
public:
struct LessThan
{
bool operator()(const E* l, const E* r) const { return (l->eqValue() < r->eqValue()); }
};
using EL=std::vector<const E*>;
using ES=std::multiset<const E*, E::LessThan>;
using ER=std::pair<ES::iterator, ES::iterator>;
static size_t NewValue() { return ++_faucet; }
~E() { eqRemove(); }
E(size_t val) : _eqValue(val) {}
E(std::string name) : Name(name), _eqValue(NewValue()) { E::Elementals.insert(this); }
//not rly a great idea to use operator=() for this. demo only..
const E& operator=(const class E& other) { eqValue(other); return *this; }
//overriddable default equivalence interface
virtual size_t eqValue() const { return _eqValue; };
//clearly it matters how mutable you need your equivalence relationships to be,,
//in this implementation, if an element's equivalence relation changes then
//the element is going to be erased and re-inserted.
virtual void eqValue(const class E& other)
{
if (_eqValue == other._eqValue) return;
eqRemove();
_eqValue=other._eqValue;
E::Elementals.insert(this);
};
ES::iterator eqRemove()
{
auto range=E::Elementals.equal_range(this);
//worst-case complexity should be aprox linear over the range
for (auto it=range.first; it!=range.second; it++)
if (this == (*it))
return E::Elementals.erase(it);
return E::Elementals.end();
}
std::string Name; //some other attribute unique to the instance
static ES Elementals; //canonical set of elements with equivalence relations
protected:
size_t _eqValue=0;
};
size_t E::_faucet=0;
E::ES E::Elementals{};
//////////////////////////////////////
//random specialisation providing
//dynamic class-level equivalence
class StarFish : public E
{
public:
static void EqAssign(const class E& other)
{
if (StarFish::_id == other.eqValue()) return;
E el(StarFish::_id);
auto range=E::Elementals.equal_range(&el);
StarFish::_id=other.eqValue();
E::EL insertList(range.first, range.second);
E::Elementals.erase(range.first, range.second);
E::Elementals.insert(insertList.begin(), insertList.end());
}
StarFish() : E("starfish") {}
//base-class overrides
virtual size_t eqValue() const { return StarFish::_id; };
protected: //equivalence is a the class level
virtual void eqValue(const class E& other) { assert(0); }
private:
static size_t _id;
};
size_t StarFish::_id=E::NewValue();
//////////////////////////////////////
void eqPrint(const E& e)
{
std::cout << std::endl << "elementals equivalent to " << e.Name << ": ";
auto range=E::Elementals.equal_range(&e);
for (auto it=range.first; it!=range.second; it++)
std::cout << (*it)->Name << " ";
std::cout << std::endl << std::endl;
}
//////////////////////////////////////
void eqPrint()
{
for (auto it=E::Elementals.begin(); it!=E::Elementals.end(); it++)
std::cout << (*it)->Name << ": " << (*it)->eqValue() << " ";
std::cout << std::endl << std::endl;
}
//////////////////////////////////////
int main()
{
E e0{"zero"}, e1{"one"}, e2{"two"}, e3{"three"}, e4{"four"}, e5{"five"};
//per the OP
e0=e1=e2;
e3=e4;
e5=e3;
eqPrint(e0);
eqPrint(e3);
eqPrint(e5);
eqPrint();
StarFish::EqAssign(e3);
StarFish starfish1, starfish2;
starfish1.Name="fred";
eqPrint(e3);
//re-assignment
StarFish::EqAssign(e0);
e3=e0;
{ //out of scope removal
E e6{"six"};
e6=e4;
eqPrint(e4);
}
eqPrint(e5);
eqPrint(e0);
eqPrint();
return 0;
}
online demo
NB: C++ class inheritance also provides another kind of immutable equivalence that can be quite useful ;)

Resources