Stuck in very interesting problem.
You might have done this before in C/C++
map<string, string> dict;
dsz = dict.size();
vector<string> words;
int sz = words.size();
for(int i = 0; i < sz; ++i)
{
for(int j = i + 1; j < dsz; ++j)
{
}
}
How I will achieve the same thing using iterator.
Please suggest.
Ok.
I figure it out.
more precisely I wanted both i and j in inner loop.
here i did with iterator, sorry I have to move to multimap instead of map due to change in requirement.
vector<string>::iterator vit;
multimap<string, string>::iterator top = dict.begin();
multimap<string, string>::iterator mit;
for(vit = words.begin(); vit != words.end(); ++vit)
{
string s = *vit;
++top;
mit = top;
for(; mit != dict.end(); ++mit)
{
/* compare the value with other val in dictionary, if found, print their keys */
if(dict.find(s)->second == mit->second)
cout << s <<" = "<< mit->first << endl;
}
}
Any other efficient way to do this will be grateful.
Your final intent is not fully clear, because you start the j loop on i+1 (see comments at the end). Until you give clarity on this relationship, I propose you two interim solutions
Approach 1: easy and elegant:
You use the new C++11 range based for(). It makes use of an iterator starting with begin() and going until end(), without you having to bother with this iterator:
for (auto x : words) { // loop on word (size sz)
for (auto y : dict) { // loop on dict (size dsz)
// do something with x and y, for example:
if (x==y.first)
cout << "word " << x << " matches dictionary entry " << y.second << endl;
}
}
Approach 2: traditional use of iterators
You cas also specify explicitely iterators to be used. This is a little bit more wordy as the previous example, but it allows you to choose the best suitable iterator, for example if you want constant iterator like cbegin() instead of begin(), if you want to skip some elements or use an adaptator on the iterator, suc as for example reverse_iterator, etc.:
for (auto itw = words.begin(); itw != words.end(); itw++) {
for (auto itd = dict.begin(); itd != dict.end(); itd++) {
// do simething with *itw and *itd, for example:
if (*itw == itd->first)
cout << "word " << *itw << " matches dictionary entry " << itd->second << endl;
}
}
Remarks:
The starting of intter loop with j=i+1 makes sense only if elements of word vector are related to elements in dict map (ok, they are cerainly words as well), AND if the order of elements you access in the map is related to the order in the vector. As map is ordered according to the key, this would make sense only word would be ordered as well following the same key. Is it the case ?
If you'd still want to skip elements or make calculation based on distance between elements , you'd rather consider the second approach propose above. It makes it easier to use distance(itw, words.begin()) which would be the equivalent of i.
However, it's best to use containters taking advantage of their design. So instead of iterating trough a dictionaly map to find a word entry, it's better to do use the map as follows:
for (auto x : words) { // loop on word (size sz)
if (dict.count(x)) // if x is in dictionary
cout << "word " << x << " matches dictionary entry " << dict[x] << endl;
}
Related
When I iterate over a vector using an int (say i), I can easily say:
vector<string> V;
V[i][g]
in which (int) g is the g'th character of the string in V[i]
When I am in a loop and want to keep iterating although I will delete items (from V) on the run, I want to make use of:
vector<string>::iterator it;
and then, I thought, the g'th character of V[i] would - in the loop - be:
for (it = V.begin() ; it != V.end() ; it++)
*it[g]
or, more logically in my eyes:
it[g]
bit neither work... Can anyone tell me how to get the g'th char of V[i] in this iterator-using variant?
What you want to do is
for (std::vector<std::string>::iterator it = V.begin(); it!=V.end(); it++) {
std::cout << *it << std::endl; // whole string
std::cout << (*it)[2] << std::endl; // third letter only
}
I have a list
list<pair<Zeitpunkt, double>> l_tempdiff;
And I only want to cout the first 5 elements.
I only know the way of couting the whole list with:
for (auto elem : l_tempdiff)
{
cout << elem.first << elem.second << endl;
}
I dont know how to acces my elements when I use:
for (it = l_tempdiff.begin(); it != l_tempdiff.end(); ++it)
{
}
And I guess I need to change the l_tempdiff.end() to some other value but it doesnt seem to take just the number5`. How can I do this?
Since std::list iterators are not random access you cannot just increment them like l_tempdiff.begin() + 5. What you can do is use std::next to increment the iterator the required number of times. That would looks like
for (auto it = l_tempdiff.begin(), end = std::next(l_tempdiff.begin(), 5); it != end; ++it)
{
// use `*it` here
}
Before doing this though you should make sure the list is big enough because if it isn't then you'll have undefined behavior.
You only want to output the first five elements?
Well, a for-range-loop is a good place to start, just add the additional constraint as a break-condition:
int i = 0;
for (auto&& elem : l_tempdiff)
{
if (5 < ++i) break;
cout << elem.first << elem.second << endl;
}
I change auto to auto&& to avoid needless copying.
As an aside, consider reading "Why is "using namespace std" considered bad practice?" and "C++: "std::endl" vs "\n"".
list<pair<Zeitpunkt,double> > :: iterator it;
int m = 0;
it = l_tempdiff.begin();
while( it != l_tempdiff.end() && m < 5)
{
cout<<it->second<<"\n";
m++;
it++;
}
Try
auto it = l_tempdiff.begin();
auto end = l_tempdiff.end();
for (int count = 0; count < 5 && it != end; ++count)
{
std::cout << it->first << it->second << std::endl;
std::advance(it);
}
This prints the first five pairs (or all the pairs, if there are less than 5).
count is used to control the maximum number of elements to be printed.
it is an iterator that, in each iteration of the loop, references the current pair.
Note that advancing an end iterator gives undefined behaviour. So it is necessary to terminate the loop if the end iterator is reached (hence the it != end test in the loop condition) or if the maximum number of elements (5) is reached.
What I'm confused about is that I have a map which is made up of size_t of string as the key, and strings as the value.
std::multimap<size_t, std::string> wordMap;
Then I have a pair that stores the equal_range for all strings with size of 4. Then I want to iterate through the start of that equal_range to the end of that equal_range. The start is my pair.first and end is my pair.second. How would I iterate through every character that my pair.first points too and then compare that to every word in between pair.first and pair.second ?
pair<multimap<size_t, string>::iterator, multimap<size_t, string>::iterator> key_range;
key_range = wordMap.equal_range(n);
Basically I want to compare every letter in word1 to every character in word2.
Advance itr2 which is word2 to the next word and compare every letter in that to every letter in word1. Do this for every word then advance itr1 which is word1 to another word and compare that to every word.
How would I get every character itr2 points to? I think the first for loop accomplishes this for the first iterator but I don't know how to do it for itr2.
for (word_map::iterator itr = key_range.first; itr != key_range.second; itr++) { //this loop will iterate through every word to be compared
for (word_map::iterator itr2 = next(key_range.first); itr2 != key_range.second; itr2++) { //this loop will iterate through every word being compared against itr1
int i = 0;
int hit = 0;
for (char& c1 : itr->first) {
char& c2{ (itr2)->first[i] };
if(c1 != c2)
hit++;
i++;
}
}
I'd like to compare every letter in every word against each other as long as they have the same string size. Then if hit == 1 that means the words are only off by 1 character and they should be mapped or stored in some type of STL container that groups them. I'm still new to STL so i'm thinking a set but I need to read more into it.
First, you'd be more likely to get assistance if you provided a minimal compilable example. I'm assuming your words are std::strings for this answer, but you know what they say about assuming.
There are algorithms like "zip" which is implemented in Boost specifically for iterating over mulitple collections simultaneously, but I don't think there's anything comparable in the standard library.
A simple but unpleasantly fiddly approach would be just to manually iterate through both strings. This will output each letter in the two words until either one word ends, or there's a difference.
Note all the fiddly bits: you need to make sure both iterators are valid at all times in case one word ends before the other, and working out what actually happened is a bit cumbersome.
#include <string>
#include <iostream>
int main()
{
std::string word1 = "capsicum";
std::string word2 = "capsicube";
std::string::iterator it1 = word1.begin();
std::string::iterator it2 = word2.begin();
while (it1 != word1.end() && it2 != word2.end())
{
// characters are different!
if (*it1 != *it2)
break;
// characters are the same
std::cout << "Both have: " << *it1 << std::endl;
// advance both iterators
++it1;
++it2;
}
if (it1 == word1.end() && it2 == word2.end())
{
std::cout << "Words were the same!" << std::endl;
}
else if (it1 == word1.end())
{
std::cout << "Word 1 was shorter than word 2." << std::endl;
}
else if (it2 == word2.end())
{
std::cout << "Word 1 was longer than word 2." << std::endl;
}
else
{
std::cout << "Words were different after position " << (it1 - word1.begin())
<< ": '" << *it1 << "' vs '" << *it2 << "'" << std::endl;
}
}
New answer, since the question was significantly updated. I'm still not sure this will do exactly what you want, but I think you should be able to use it to get where you want to go.
I've written this as a minimal, complete, verifiable example, which is ideally how you should pose your questions. I've also used C++11 features for brevity/readability.
Hopefully the inline comments will explain things sufficiently for you to at least be able to do your own research for anything you don't fully understand, but feel free to comment if you have any more questions. The basic idea is to store the first word (using the key_range.first iterator), and then start iterating from the following iterator using std::next(), until we reach the end iterator in key_pair.second.
This then gives us word1 outside of the loop, and word2 within the loop which will be set to every other word in the list. We then use the "dual interation" technique I posted in my other answer to compare each word character by character.
#include <map>
#include <string>
#include <iostream>
int
main()
{
std::multimap<size_t, std::string> wordMap;
wordMap.insert({4, "dogs"});
wordMap.insert({4, "digs"});
wordMap.insert({4, "does"});
wordMap.insert({4, "dogs"});
wordMap.insert({4, "dibs"});
// original type declaration...
// std::pair<std::multimap<size_t, std::string>::iterator, std::multimap<size_t, std::string>::iterator> key_range;
// C++11 type inference...
auto key_range = wordMap.equal_range(4);
// make sure the range wasn't empty
if (key_range.first == key_range.second)
{
std::cerr << "No words in desired range." << std::endl;
return 1;
}
// get a reference to the first word
std::string const& word1 = key_range.first->second;
std::cout << "Comparing '" << word1 << "' to..." << std::endl;
// loop through every iterator from the key_range, skipping for the first
// (since that's the word we're comparing everything else to)
for (auto itr = std::next(key_range.first); itr != key_range.second; ++itr)
{
// create a reference for clarity
std::string const& word2 = itr->second;
std::cout << "... '" << word2 << "'";
// hit counter; where hit is defined as characters not matching
int hit = 0;
// get iterators to the start of each word
auto witr1 = word1.begin();
auto witr2 = word2.begin();
// loop until we reach the end of either iterator. If we're completely
// confident the two words are the same length, we could only check
// one of them; but defensive coding is a good idea.
while (witr1 != word1.end() && witr2 != word2.end())
{
// dereferencing the iterators will yield a char; so compare them
if (*witr1 != *witr2)
++hit;
// advance both iterators
++witr1;
++witr2;
}
// do something depending on the number of hits
if (hit <= 1)
{
std::cout << " ... close enough!" << std::endl;
}
else
{
std::cout << " ... not a match, " << hit << " hits." << std::endl;
}
}
}
I have 4 vectors with about 45,000 records each right now. Looking for an efficient method to run through these 4 vectors and output how many times it matches the users input. Data needs to match on the same index of each vector.
Multiple for loops? Vector find?
Thanks!
If the elements need to match at the same location, it seems that a std::find() or std::find_if() combined with a check for the other vectors at the position is a reasonable approach:
std::vector<A> a(...);
std::vector<B> b(...);
std::vector<C> c(...);
std::vector<D> d(...);
std::size_t match(0);
for (auto it = a.begin(), end = a.end(); it != end; ) {
it = std::find_if(it, end, conditionA));
if (it != end) {
if (conditionB[it - a.begin()]
&& conditionC[it - a.begin()]
&& conditionD[it - a.begin()]) {
++match;
}
++it;
}
}
What I got from description is that, you have 4 vectors and lots of user data, you need to find out how many of times it matches with vectors at same index
so here goes the code ( i am writing a c++4.3.2 code)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
vector<typeT>a;
vector<typeT>b;
vector<typeT>c;
vector<typeT>d;
vector<typeT>matched;
/*i am assuming you have initialized a,b,c and d;
now we are going to do pre-calculation for matching user data and store
that in vector matched */
int minsize=min(a.size(),b.size(),c.size(),d.size());
for(int i=0;i<minsize;i++)
{
if(a[i]==b[i]&&b[i]==c[i]&&c[i]==d[i])matched.push_back(a[i]);
}
return 0;
}
this was the precalculation part. now next depend on data type you are using, Use binary search with little bit of extra counting or using a better data structure which stores a pair(value,recurrence) and then applying binary search.
Time complexity will be O(n+n*log(n)+m*log(n)) where n is minsize in code and m is number of user input
Honestly, I would have a couple of methods to maintain your database(vectors).
Essentially, do a QuickSort to start out with.
Then ever so often consistently run a insertion sort (Faster then QuickSort for partially sorted lists)
Then just run binary search on those vectors.
edit:
I think a better way to store this is instead of using multiple vectors per entry. Have one class vector that stores all the values. (your current vectors)
class entry {
public:
variable data1;
variable data2;
variable data3;
variable data4;
}
Make this into a single vector. Then use my method I described above to sort through these vectors.
You will have to sort through by what type of data it is first. Then after call binary search on that data.
You can create a lookup table for the vector with std::unordered_multimap in O(n). Then you can use unordered_multimap::count() to get the number of times the item appears in the vector and unordered_multimap::equal_range() to get the indices of the items inside your vector.
std::vector<std::string> a = {"ab", "ba", "ca", "ab", "bc", "ba"};
std::vector<std::string> b = {"fg", "fg", "ba", "eg", "gf", "ge"};
std::vector<std::string> c = {"pq", "qa", "ba", "fg", "de", "gf"};
std::unordered_multimap<std::string,int> lookup_table;
for (int i = 0; i < a.size(); i++) {
lookup_table.insert(std::make_pair(a[i], i));
lookup_table.insert(std::make_pair(b[i], i));
lookup_table.insert(std::make_pair(c[i], i));
}
// count
std::string userinput;
std::cin >> userinput;
int count = lookup_table.count(userinput);
std::cout << userinput << " shows up " << count << " times" << std::endl;
// print all the places where the key shows up
auto range = lookup_table.equal_range(userinput);
for (auto it = range.first; it != range.second; it++) {
int ind = it->second;
std::cout << " " << it->second << " "
<< a[ind] << " "
<< b[ind] << " "
<< c[ind] << std::endl;
}
This will be the most efficient if you will be searching the lookup table many items. If you only need to search one time, then Dietmar Kühl's approach would be most efficient.
The Vector find function can search an inserted value even if you try and find by providing substring . Is this same in case of the keys of a map ?
int main()
{
vector<string> v;
v.push_back("text");
v.push_back("[[text");
v.push_back("text");
for (unsigned i = 0; i < v.size(); i++)
{
if (v[i].find("[[") == 0)
{
v[i].append("]]");
}
}
}
Here it finds "[[text" and makes it "[[text]]" .
I tried it in map but code crashes on run time ,. I am using Dev c++
int main()
{
std::multimap<string, string> m;
std::multimap<string, string> intersection;
std::multimap<string, string>::iterator it8;
m.insert(pair< string, string>("4-2"," 61-7" ));
m.insert(pair< string, string>("5-2"," 61-7" ));
multimap<string, string>::iterator it4;
multimap<string, string>::iterator it5;
for ( it4 = m.begin(); it4 !=m.end(); it4++)
{
if (m.find("5-") == 0)
it5=it4;
}
cout << " result of 5 search is" << (*it5).first << ", " << (*it5).second <<endl;
m.clear();
getchar();
}
(Sample correct code on ideone)
The error is that this line
if (m.find("5-") == 0)
will never succeed. You maybe be surprised at this. m.find("5-") searches through the entire map looking for an entry whose key is exactly equal to "5-". Your keys are "4-2" and "5-2".
Do you wish to find keys which contain the substring "5-"? Then you need something like
it4->first.find("5-"); // check if the key string at this entry contains "5-"
I think you want a loop like this:
multimap<string, string>::iterator it4;
for ( it4 = m.begin(); it4 !=m.end(); it4++)
{
if (it4->first.find("5-") != string :: pos)
cout << " result of 5 search is" << it4->first << ", " << it4->second <<endl;
}
As others have pointed out, you are not interested in the the find method of vector or map. You are interested in the find method of string - this is quite different. The title of your question is a little misleading as a result (unintentionally).
The problem with std::set<> is that you cannot modify its elements in place because you could violate the ordering it has. You can however iterate from set.begin() to set.end() using iterators (instead of operator[]) and remove and reinsert modified elements.