finding the largest set within a map - c++

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, " "))

Related

How to erase element from std::vector<string> by its length(erase not working)

i have given a vector `
vector<string> inputArray = { "aba","aa","ad","vcd","aba" };
and i want to return this vector which contains only string with the longest length, in this case i want to return only {"aba","vcd","aba"}, so for now i want to erase elements which length is not equal to the highest `
vector<string> allLongestStrings(vector<string> inputArray) {
int length = inputArray.size();
int longstring = inputArray[0].length();
int count = 0;
vector<string> result;
for (int i = 0; i < length; i++)
{
if (longstring < inputArray[i].length())
{
longstring = inputArray[i].length();
}
count++;
}
for (int = 0; i<count;i++)
{
if (inputArray[i].length() != longstring)
{
inputArray[i].erase(inputArray.begin() + i);
count--;
i--;
}
}
return inputArray;
}
but i get this error no instance of overloaded fucntion "std::basic_string<_Elem,_Traits,_Alloc>::erase[with_Elem=char,_Traits=std::char_traits<char>,_Alloc=std::allocator<char>]" matches the argument list" in inputArray[i].erase(inputArray.begin()+i); this line
what's wrong?
There are other problems, but this specific compiler message is telling you that's not the right way to remove specific character(s) from a string.
However, reading the question in the OP, we see that you wanted to remove a string from a vector. To fix that one specific error, simply change
inputArray[i].erase( /*character position(s) in the string*/ )
to
inputArray.erase( /*some position in the array*/ )
Or you could fix it so it uses an iterator in the string denoted by inputArray[i] to actually delete characters from that string, which of course isn't what you said you wanted to do. The point is, the error message is because you're using the wrong iterator type because you think that you're working with a vector, but you actually told it to work with a string that you got out of the vector.
And then you will compile and have other issues which are well covered in comments already.
The issue with inputArray[i].erase(inputArray.begin() + i); can be fixed as shown in Kenny Ostrom's answer.
I'd like to point out that the OP could make use of the erase-remove idiom or even create a new vector with only the bigger strings instead (the posted code is already copying the source vector).
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
template <typename InputIt>
auto only_the_longest_of(InputIt first, InputIt last)
{
using value_type = typename std::iterator_traits<InputIt>::value_type;
std::vector<value_type> result;
// find the longest size
auto longest = std::max_element(first, last,
[](value_type const &a, value_type const &b) {
return a.size() < b.size();
});
if ( longest == last )
return result;
// extract only the longest ones, instead of erasing
std::copy_if( first, last, std::back_inserter(result)
, [max_size = longest->size()] (value_type const& v) {
return v.size() >= max_size;
});
return result;
}
template <typename T>
auto erase_the_shortest_from(std::vector<T> &input)
{
// find the longest size
auto longest = std::max_element(input.cbegin(), input.cend(),
[](T const &a, T const &b) {
return a.size() < b.size();
});
if ( longest == input.cend() || longest->size() == 0 )
return input.end();
// implement erase-remove idiom
return input.erase(std::remove_if(
input.begin(), input.end(), [max_size = longest->size()] (T const &v) {
return v.size() < max_size;
}));
}
int main()
{
std::vector<std::string> test = {
"aba", "aa", "ad", "vcd", "aba"
};
// The original vector remain unchanged
auto result = only_the_longest_of(test.cbegin(), test.cend());
for (auto const& str : result)
std::cout << str << '\n';
std::cout << '\n';
// This will change the vector
erase_the_shortest_from(test);
for (auto const& str : test)
std::cout << str << '\n';
}

How to apply the concept of counting occurrences on strings variables in C++

following program ca calculate the frequency of ints in an array
how to apply this concept on string variable because a string is also an array on the back end
using namespace std;
int counter[10]={0,0,0,0,0,0,0,0,0,0};
int arr [9][9],x;
int main()
{
srand(time(NULL));
cout<<"enter the array \n";
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
arr[i][j]=rand()%10;
}
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
counter[arr[i][j]]++;
}
}
for(int j=0;j<10;j++){
cout<<j<<" : "<< counter[j]<<endl;
}
return 0;
}
Here is how one can count occurrences of anything from anything:
Code
#include <iterator>
#include <map>
#include <algorithm>
template<class InputIt>
auto
occurrences(InputIt begin, InputIt end)
{
std::map<typename std::iterator_traits<InputIt>::value_type, std::size_t> result;
std::for_each(begin, end, [&result](auto const& item){ ++result[item]; });
return result;
}
Usage
#include <string>
#include <iostream>
int main()
{
auto text = std::string{"Hello, World!"};
auto occ = occurrences(begin(text), end(text));
std::cout << occ['l'] << '\n'; // outputs 3
}
Live demo
Explanation
template<class InputIt>
This is a generic (template) function iterating over any input iterator.
auto
Its return type is inferred from its implementation. Spoiler alert: it is a std::map of (value counter, occurrence of this value).
occurrences(InputIt begin, InputIt end)
occurrences is called with a couple of iterators defining a range, generally calling begin(C) and end(C) on your container C.
std::for_each(begin, end, //...
For each element in the range...
[&result](auto const& item){ //...
...execute the following treatment...
++result[item]; });
...increment the occurrence count for the value item, starting with zero if its the first.
This is not an efficient implementation since it copies the values it counts. For integers, characters, etc. its perfect but for complex types you might want to improve this implementation.
It's generic and standard container compatible. You could count anything iterable.
If I understand correctly, you want to count occurrences of strings. STL container map is useful for this purpose. Following is example code.
#include<iostream>
#include<map>
#include<string>
#include<vector>
int main()
{
std::vector<std::string> arrayString;
std::map<std::string, int> counter;
std::map<std::string, int>::iterator it;
arrayString.push_back("Hello");
arrayString.push_back("World");
arrayString.push_back("Hello");
arrayString.push_back("Around");
arrayString.push_back("the");
arrayString.push_back("World");
// Counting logic
for(std::string strVal : arrayString)
{
it = counter.find(strVal);
if(it != counter.end())
it->second += 1; // increment count
else
counter.insert(std::pair<std::string, int>(strVal, 1)); // first occurrence
}
// Results
for(std::map<std::string, int>::iterator it = counter.begin(); it != counter.end(); ++it)
std::cout << it->first << ": " << it->second << std::endl;
return 0;
}
More compact way to write the counting logic is :
// Counting logic
for(std::string strVal : arrayString)
{
++counter[strVal]; // first time -> init to 0 and increment
}

get the element from a Map with a given value in the Value

I have a map defined as std::map<std::string, textInfo> tempMap;
the textInfo class has some attributes as textsize,textcolor,textfont etc..
I want to select an item from this map that matches with a given value to an attribute in textInfo class.
for example if the Map contains
<"A",textInfo("10","Red","Verdana")>
<"B",textInfo("12","Green","Timesnewroman")>
<"C",textInfo("11","Blue","Cambria")>
I want to select the item that contains "Cambria" in it textfont attribute.
<"C",textInfo("11","Blue","Cambria")>
std::find_if should work for your needs.
Sample program:
#include <iostream>
#include <map>
#include <algorithm>
struct textInfo
{
std::string textsize;
std::string textcolor;
std::string textfont;
};
int main()
{
std::map<std::string, textInfo> m =
{
{"A", {"10","Red","Verdana"}},
{"B", {"12","Green","Timesnewroman"}},
{"C", {"11","Blue","Cambria"}}
};
auto iter = std::find_if(m.begin(),
m.end(),
[](std::pair<std::string, textInfo> const& item)
{ return (item.second.textfont == "Cambria");});
if ( iter != m.end() )
{
auto& item = iter->second;
std::cout << item.textsize << ", " << item.textcolor << ", " << item.textfont << std::endl;
}
}
Output:
11, Blue, Cambria
You can only access maps directly via a key, here your std::string. To search for a value or even a variable inside a value like it's the case here you have to iterate over the whole map.
std::map<std::string, textInfo>::const_iterator it = tempMap.begin();
for (; it != tempMap.end(); ++it)
{
if (0 == tempMap[(*it)].textfont.equals("Cambria")) // You could use == operator if it's a std::string
{
break; // found
}
}
// Do something with the found item. If the iterator is tempMap.end(), nothing found!
Look here for more informations.

How to use iterator to update element of 2D string vector

See this code. I need to change the value of a specific element in a 2D string vector using the iterator. I can use for loop with an index to do this. but here what i need is directly use the iterator to refer the element. something like (*ite)[0] = "new name"
Any idea? I added full working code here for your convenience
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
string convertInt(int number)
{
stringstream ss;
ss << number;
return ss.str();
}
int main()
{
vector<vector<string>> studentList;
for(int i=0; i<10; i++){
vector<string> student;
student.push_back("name-"+convertInt(i));
student.push_back(convertInt(i+10));
studentList.push_back(student);
}
vector<string> temp;
for(vector<vector<string>>::iterator ite = studentList.begin(); ite != studentList.end(); ++ite){
temp = *ite;
if(temp[0].compare("name-5")==0){
cout << "Changeing the name of student 5" << endl;
// I need to change the studentList[5][0] (original value not the one in temp vector) at here using iterator ite
}
}
return 0;
}
Because temp = *ite makes a copy of vector(student), if you modify on temp, it's not modified on real studentList, that's why you need (*ite)[0] = "new name" to change value on real element.
Using for loop is a bit "ugly", use std::find_if instead of for loop:
bool IsFindFifthName(const std::vector<std::string>& student)
{
return student[0] == "name-5";
}
std::vector<std::vector<std::string>>::iterator iter
= std::find_if(studentList.begin(), studentList.end(), IsFindFifthName);
if (iter != studentList.end() )
{
(*iter)[0] = " new name";
}
Or use Lambda if C++11 is available:
std::vector<std::vector<std::string>>::iterator iter
= std::find_if(studentList.begin(), studentList.end(),
[](std::vector<std::string>& student){ return student[0] == "name-5"; });
if (iter != studentList.end() )
{
(*iter)[0] = " new name";
}
Using STL algorithm Transform in case could a good option. The algorithm internally uses iterators. A Sample example:
typedef std::vector<std::string> VectorOfString;
void DisplayStudent(const std::vector<VectorOfString>& StudentList)
{
std::for_each(StudentList.cbegin(), StudentList.cend(),
[](const VectorOfString& vectorElement)
{
std::for_each(vectorElement.cbegin(), vectorElement.cend(),
[](const std::string& value)
{
std::cout << value << endl;
});
});
}
std::vector<VectorOfString> StudentList;
std::string data1 = "One";
std::string data2 = "Two";
VectorOfString data(2);
data.push_back(data1);
data.push_back(data2);
StudentList.push_back(data);
DisplayStudent(StudentList);
std::for_each(std::begin(StudentList), std::end(StudentList),
[](VectorOfString& vectorElement)
{
std::transform(std::begin(vectorElement), std::end(vectorElement), std::begin(vectorElement),
[](std::string& value)-> std::string
{
if(value.compare("One") == 0)
return "OneOne";
else
return value;
});
});
DisplayStudent(StudentList);

count of elements in a set (not total count)

I have a set of strings in c++.
i am inserting into that set as :
m.insert("1-2-35-2");
m.insert("1-2-36-1");
m.insert("1-2-37-2");
m.insert("1-2-38-1");
m.insert("1-2-39-2");
m.insert("2-2-40-1");
m.insert("2-2-41-2");
m.insert("2-2-42-1");
m.insert("1-2-43-2");
m.insert("1-2-44-1");
m.insert("1-2-45-2");
m.insert("1-2-46-1");
m.insert("1-2-47-2");
i want to calculate the count of all the strings inside the set which start with "2-"(count =3) and also which start with "1-"(count=10).
is there any way to do it.
I tried with lower_bound and upper_bound but its giving me some errors.
errors are coming for the statement:
int i=it_upper-it_lower;
I am using solaris SPARC OS.
i just tested this program
#include <iostream>
#include <iterator>
#include <list>
using namespace std;
int main () {
list<int> mylist;
for (int i=0; i<10; i++) mylist.push_back (i*10);
list<int>::iterator first = mylist.begin();
list<int>::iterator last = mylist.end();
cout << "The distance is: " << distance(first,last) << endl;
return 0;
}
it gives me compilation error:
line 13: Error: Could not find a match for std::distance<std::ForwardIterator, std::Distance>(std::list<int, std::allocator<int>>::iterator, std::list<int, std::allocator<int>>::iterator).
1 Error(s) detected.
Sorry. Wrong answer
Update:
count_if is an algorithm to count elements based on function. Try like in this example:
bool struct key_part: public std::unary_function< std::string, bool >
{
std::string _part;
key_part(const std::string part):_part(part){}
bool operator()(std::string &s)
{
return s.find(_part)!=std::string::npos;
}
}
std::count_if( m.begin(), m.end(), key_part("1-") );
It will count all elements that contains "1-" as part of key
If you have a modern compiler that supports lambdas, you could use those as the predicate to count_if:
auto if_s_1 = [](const std::string &s) { return s.find("1-") == 0; }
auto if_s_2 = [](const std::string &s) { return s.find("2-") == 0; }
int count1 = std::count_if(m.begin(), m.end(), if_s_1);
int count2 = std::count_if(m.begin(), m.end(), if_s_2);