Erasing case in-sensitive duplicates from std::vector<std::string> - sorting

This is weird, can't erase remove case in-sensitive duplicates from std::vector? Can someone please let me know how to achieve this? Here is my code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> stringVec = {"John", "Bob", "Joe", "Zack", "Randy", "bob", "joe", "andy"};
sort(stringVec.begin(), stringVec.end());
stringVec.erase(unique(stringVec.begin(), stringVec.end()),stringVec.end());
for(unsigned i=0; i<stringVec.size(); i++)
{
cout<<stringVec[i]<<endl;
}
return 0;
}
Output for above code:
Success time: 0 memory: 3432 signal:0
Bob
Joe
John
Randy
Zack
andy
bob
joe
I expect at least joe, bob to be removed and andy to be placed in first index.

You can solve this by passing a case-insensitive predicate to both sort() and unique():
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
string lowercase(string x)
{
transform(x.begin(), x.end(), x.begin(), [](char x) { return tolower(x); });
return x;
}
int main()
{
vector<string> stringVec = {"John", "Bob", "Joe", "Zack", "Randy", "bob", "joe", "andy"};
sort(stringVec.begin(), stringVec.end(),
[](const string &a, const string &b) { return lowercase(a) < lowercase(b); }
);
stringVec.erase(
unique(stringVec.begin(), stringVec.end(),
[](const string &a, const string &b) { return lowercase(a) == lowercase(b); }
),
stringVec.end()
);
for(unsigned i=0; i<stringVec.size(); i++)
{
cout<<stringVec[i]<<endl;
}
return 0;
}
Live example

Related

Error E0146 : Too many initializer values C++

I have a school project and I have to use the AM in the Student.h as a char*.The AM have to have numbers in it. I can't understand why what I am doing is not working.
Student.cpp
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
int main()
{
Student dlg;
dlg.AM[10]={2,1,3,9,0,2,6,6};
}
Student.h
#pragma once
#include <string>
using namespace std;
class Student
{
public:
char *AM[20];
string Name;
unsigned int Semester = 1;
};
If you really need your student number to be a char string, then you need to convert your ints to char* before assigning them to the array.
int main()
{
Student dlg;
int j = 0;
for (auto i : {2,1,3,9,0,2,6,6})
{
auto strInt { std::to_string(i) }; // create a C++ string containing a int
// next copy the internal memory of the C++ string to a read-writable memory buffer
// and assign a pointer to that buffer casted to a char* to the appropriate slot in the array
dlg.AM[j++] = static_cast<char*> (std::memcpy (new char[16], strInt.c_str(), strInt.size()));
}
// test
for (int i = 0; i < 8; i++)
{
cout << dlg.AM[i] << ' ';
}
}
Are you sure the student number should be a char* ?

Sorting vector of objects c++ raise C2280 error

I have a vector of Workout objects, and I want to sort it by the prices of the workout (each Workout have const field price and getPrice function)
When Im trying to sort the array i get a C2280 error -
Workout &Workout::operator =(const Workout &)': attempting to reference a deleted function
#ifndef WORKOUT_H_
#define WORKOUT_H_
#include <string>
class Workout {
public:
Workout(int w_id, std::string w_name, int w_price, WorkoutType w_type);
int getPrice() const;
Workout& operator =(const Workout& other)
{
if (this == &other) return *this;
return *new(this) Workout(other.getId(), other.getName(),
other.getPrice(), other.getType());
}
private:
const int price;
};
I else have virtual class Customer and cheapCustomer object that inheritence from it, and function- order(const std::vector& workout_options) that needs to sort the vector by the prices.
Here is the Customer cpp file -
#include "Customer.h"
#include <algorithm>
using namespace std;
Customer::Customer(std::string c_name, int c_id) :name(c_name), id(c_id)
{
}
CheapCustomer::CheapCustomer(std::string name, int id) :Customer(name, id)
{
}
std::vector<int> CheapCustomer::order(const std::vector<Workout>& workout_options)
{
std::vector<int>* v = new std::vector<int>();
std::vector<Workout> tmp = workout_options;
std::sort(tmp.begin(), tmp.end(), [](const Workout& w1, const Workout& w2) {
return w1.getPrice() < w2.getPrice();
});
return *v;
//delete v
}
#include <vector>
#include "Customer.h"
#include "Trainer.h"
#include <algorithm>
using namespace std;
int main(int argc, char** argv) {
Workout w1 = Workout(1, "w1", 10, CARDIO);
Workout w2 = Workout(2, "w2", 20, CARDIO);
Workout w3 = Workout(3, "w3", 30, MIXED)
std::vector<Workout> v;
v.push_back(w1);
v.push_back(w2);
v.push_back(w3);
Customer* c_cheap = new CheapCustomer("Cheap", 20);
vector<int> order_cheap = c_cheap->order(v);
can some one please tell me how to fix it?
Thank you so much
I tried to use unique_ptr and still the same error-
C2280 'std::unique_ptr<Workout,std::default_delete>::unique_ptr(const std::unique_ptr<Workout,std::default_delete> &)': attempting to reference a deleted function
std::vector<int> CheapCustomer::order(const std::vector<Workout>& workout_options)
{
vector<int>* v = new std::vector<int>();
vector<unique_ptr<Workout>> v_unique_ptr;
for (Workout workout : workout_options) {
v_unique_ptr.push_back(unique_ptr<Workout>(new Workout(workout.getId(),workout.getName(),workout.getPrice(),workout.getType())));
}
std::sort(v_unique_ptr.begin(), v_unique_ptr.end(), [](unique_ptr<Workout> w1, unique_ptr<Workout> w2) {
return w1->getPrice() < w2->getPrice();
});
}
Edited:
its worked here
vector<int>* v = new std::vector<int>();
vector<unique_ptr<Workout>> v_unique_ptr;
for (Workout workout : workout_options) {
v_unique_ptr.push_back(move(unique_ptr<Workout>(new Workout(workout.getId(),workout.getName(),workout.getPrice(),workout.getType()))));
}
std::sort(v_unique_ptr.begin(), v_unique_ptr.end(), [](unique_ptr<Workout>& w1, unique_ptr<Workout>& w2) {
return w1->getPrice() < w2->getPrice();
});
v->push_back(v_unique_ptr[0]->getId());
return *v;
Thank you so much
In order to use std::sort, the element type needs to be move-assignable. Your element type isn't, because of all the const data members.
So you may either:
Remove the const
Provide your own move assignment operator that somehow gets around const
Don't place Workout objects in a container, place pointers instead (preferably smart pointers such as unique_ptr).

how can we add an element in the map of set...eg .map<int,unordered_multiset<int>>mp; in c++14

i want add an element to the mp[x].
map<int,unordered_multiset>adj;
for(int i=0;i<n;i++)
{
cin>>brr[i];
if(brr[i]!=arr[i])
{
// i want to add an element
//in mp[brr[i]] ;
}
else
{
comp.insert({brr[i],i+1}); //set
}
}
}
Here is an example for a map from int to unordered_multiset<int>.
#include <map>
#include <unordered_set>
#include <iostream>
int main() {
std::map<int, std::unordered_multiset<int>> adj;
const int z = 10;
adj[6].insert(z);
adj[6].insert({1,2,3});
auto& myset = adj[6];
for(auto const& x : myset) {
std::cout << x << std::endl;
}
return 0;
}
Output:
3
2
1
10
The examples on cppreference are usually quite good:
https://en.cppreference.com/w/cpp/container/map#Example
https://en.cppreference.com/w/cpp/container/map/insert#Example
And then you have to find the correct way to insert into the multiset:
https://en.cppreference.com/w/cpp/container/unordered_multiset/insert
And one of them uses the initializer_list {}

inserting a range of struct vector into a vector of a struct member type

Is it possible to insert range of struct directly into vector of the same type (same type of a member of struct).
Let's have a struct and vectors like this:
struct pnt {
char _name;
int _type;
bool _aux;
};
std::vector<pnt> pnts;
std::vector<int> pntType;
The question is that how to insert a range of pnts into pntType using single standard line of C++98:
void insert (iterator position, InputIterator first, InputIterator last);
or even Boost library.
Since I am using this often in different parts of my code, I am trying to avoid doing this in a loop. The last option is defining a function for that.
EDIT:
I know the insert syntax. What I cannot do is how to insert from pnts (only _type of each member) into pntType
UPDATE: There is a better way than my first suggestion (see bottom), since we're already using Boost. The problem with std::transform and std::insert_iterator is that v2 is resized several times, which is wasteful considering that we know the width of the range in advance. Using boost::transform_iterator and boost::bind, it is possible to avoid the problem like this:
#include <boost/bind.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
struct A {
int x;
};
int main() {
A arr[] = {
{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }
};
std::vector<A> v1(arr, arr + 6);
std::vector<int> v2;
v2.insert(v2.begin(),
boost::make_transform_iterator(v1.begin() + 2, boost::bind(&A::x, _1)),
boost::make_transform_iterator(v1.begin() + 4, boost::bind(&A::x, _1)));
std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout, "\n"));
}
OLD SUGGESTION:
boost::bind works with data member pointers, so using C++98 and Boost, you could do something like this without changing your struct:
#include <boost/bind.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
struct A {
int x;
};
int main() {
A arr[] = {
{ 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }
};
std::vector<A> v1(arr, arr + 6);
std::vector<int> v2;
// one-liner here:
std::transform(v1.begin() + 2,
v1.begin() + 4,
std::insert_iterator<std::vector<int> >(v2, v2.begin()),
boost::bind(&A::x, _1));
std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout, "\n"));
}
Using boost range:
boost::copy(pnts | transformed(std::mem_fn(&pnt::_type)), std::back_inserter(pntType));
Or even
boost::copy_range<std::vector<int>>(pnts | transformed(std::mem_fn(&pnt::_type)));
See it Live on Coliru
Note you can use boost::bind(&pnt:_type,_1) instead of mem_fn to allow for your compiler version
Updated To show with specific first/last iterators, and compiling in c++03 mode:
Live On Coliru
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/bind.hpp>
using namespace boost::adaptors;
using namespace boost;
struct pnt {
char _name;
int _type;
bool _aux;
};
int main() {
std::vector<pnt> pnts(6);
std::vector<int> pntType;
boost::copy(
make_iterator_range(pnts.begin(), pnts.begin()+3) | transformed(bind(&pnt::_type, _1)),
std::back_inserter(pntType));
}
Inserting one container into the other works like this:
pntType.insert(pntType.begin(),pnts.begin(),pnts.end());
To be able to insert the correct type, you should add a conversion operator to int to your struct.
struct pnt {
char _name;
int _type;
bool _aux;
operator int (){
return _type;
}
};

Difficulty in Implementation in Segment tree with lazy propogation

I am having trouble in implementing segment tree with lazy propagation. I just read about segment trees and tried to do a simple question (http://www.codechef.com/problems/FLIPCOIN) using it but I am getting wrong answer. Please help me with the implementation. Here is my code(If you prefer ideone:http://ideone.com/SHVZ5y):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>
#include <map>
#include <vector>
#include <list>
#include <string>
#include <set>
#include <queue>
#define s(x) scanf("%d",&x)
#define sil(x) scanf("%llu",&x)
#define sd(x) scanf("%ld",&x)
#define FOR(i,a,b) for( typeof(a) i=(a); i<(b); ++i) // exclusive for
#define FORR(i,a,b) for( typeof(a) i=(a-1) ; i>=(b); --i)
#define REP(k,a,b) for(typeof(a) k=(a); k <= (b); ++k) // inclusive for
#define REPR(i,a,b) for( typeof(a) i=(a) ; i>=(b); --i)
#define ALL(c) (c).begin(), (c).end()
#define PB push_back
#define MP make_pair
#define SZ(x) ((int)((x).size()))
#define SRT(v) std::sort(ALL(v))
#define CTN(x) std::cout<<x<<'\n' //cout with newline
#define CTS(x) std::cout<<x<<" " //cout with space
#define CLR(x) std::memset(x,0,sizeof(x))
#define FILL(x,n) std::fill_n(x,sizeof(x),n)
#define DBGA(x,n) {FOR(i,0,n) cout<<x[i]<<" "; CTN(" ");}
//#define NL printf("\n")
typedef std::vector<int> VI;
typedef std::vector<long long int> VL;
typedef std::vector<std::string> VS;
typedef std::map<int,int> MI;
typedef std::pair<int,int> PII;
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
struct node{
int h; //number of head
int t; //number of tail
int lazy;
node()
{
h=0;
t=0;
lazy=0;
}
}tree[300000];
void build_tree(int n,int a,int b)
{
//cout<<"wo"<<endl;
if(a>b)
return;
if(a==b)
{
tree[n].h=0;
tree[n].t=1;
//cout<<tree[n]<<" "<<a<<" "<<b<<" "<<n<<endl;
return;
}
build_tree(2*n+1,a,(a+b)/2);
build_tree(2*n+2,(a+b)/2+1,b);
tree[n].t=tree[2*n+1].t+tree[2*n+2].t;
//cout<<tree[n]<<" "<<a<<" "<<b<<" "<<n<<endl;
}
int query(int n,int ql,int qr,int l,int r)
{
if(tree[n].lazy!=0)
{
int tmp=tree[n].h;
tree[n].h=tree[n].t;
tree[n].t=tmp;
if(r!=l)
{
tree[2*n+1].lazy=1;
tree[2*n+2].lazy=1;
}
tree[n].lazy=0;
}
if(l>qr || r<ql)
return 0;
if(l>=ql && r<=qr)
return tree[n].h;
return query(2*n+1,ql,qr,l,(l+r)/2)+query(2*n+2,ql,qr,(l+r)/2+1,r);
}
void update(int n,int ul,int ur,int l,int r)
{
if(tree[n].lazy!=0)
{
int tmp=tree[n].h;
tree[n].h=tree[n].t;
tree[n].t=tmp;
if(r!=l)
{
tree[2*n+1].lazy=1;
tree[2*n+2].lazy=1;
}
tree[n].lazy=0;
}
if(l>ur || r<ul)
return ;
if(l>=ul && r<=ur)
{
int tmp=tree[n].h;
tree[n].h=tree[n].t;
tree[n].t=tmp;
if(r!=l)
{
tree[2*n+1].lazy=1;
tree[2*n+2].lazy=1;
}
return;
}
update(2*n+1,ul,ur,l,(l+r)/2);
update(2*n+2,ul,ur,(l+r)/2+1,r);
tree[n].h=tree[2*n+1].h+tree[2*n+2].h;
tree[n].t=tree[2*n+1].t+tree[2*n+2].t;
}
int main()
{
std::ios_base::sync_with_stdio(false);
int n;cin>>n;
build_tree(0,0,n-1);
int q;cin>>q;
while(q--)
{
int t;cin>>t;int l,r;cin>>l>>r;
if(t)
{
cout<<query(0,l,r,0,n-1)<<'\n';
}
else
{
update(0,l,r,0,n-1);
/*CTN(" ");
FOR(i,0,7)
cout<<i<<" "<<tree[i].h<<'\n';
CTN(" ");*/
}
}
}
There was a problem with the lazy propagation part. It should be:
tail[2*n+1].lazy=1-tail[2*n+1].lazy
and not
tail[2*n+1].lazy=1

Resources