i have a recursive search function that returns the index of my vector where the search key was found
However sometimes my vector can have two different positions that have the same key but my function only returns the first one.
here is my function:
int IdeaBank::twoSearchAND(int first, int last, string word_1, string word_2)
{
if (last == first)
return -1;
if (newIdea[first].foundWordInBoth(word_1)
&& newIdea[first].foundWordInBoth(word_2))
return first;
else
return twoSearchAND(first+1,last,word_1,word_2);
}
and here is how i am using it in my main
int first = 0;
int last = ideaBank.newIdea.size();
int index_found;
index_found = ideaBank.twoSearchAND(first, last, search_word1, search_word2);
ideaBank.displayIdeaByID(index_found);
my idea was to loop through n amount of times were n is the number of index's it returns but i wasnt too sure how to achieve that
is there a way for me to get all the returned values from my function?
Edit: this is for a school project and must use recursion
A function can return at most one value. However, a class can have multiple sub objects. Therefore you can return multiple sub objects within one return by returning a class. To return exactly two values, you can use std::pair for example.
Note that this algorithm is already in the standard libarary: std::search_n, so there is no need to re-write it. Also, it is an inherently iterative algorithm and there is no need to complicate it by using recursion.
You might collect results into a container such as std::vector.
To avoid extra copies to concatenate vectors if used as return value, I use it as output parameter in the recursive method.
void IdeaBank::twoSearchAND(int first, int last,
const std::string& word_1, const std::string& word_2,
std::vector<int>& res)
{
if (last == first)
return;
if (newIdea[first].foundWordInBoth(word_1)
&& newIdea[first].foundWordInBoth(word_2))
res.push_back(first);
twoSearchAND(first + 1, last, word_1, word_2, res);
}
std::vector<int> IdeaBank::twoSearchAND(const std::string& word_1,
const std::string& word_2)
{
std::vector<int> res;
int first = 0;
int last = newIdea.size();
twoSearchAND(first, last, word_1, word_2, res);
return res;
}
And usage is similar to:
auto indexes_found = ideaBank.twoSearchAND(search_word1, search_word2);
for (auto index_found : indexes_found) {
ideaBank.displayIdeaByID(index_found);
}
Related
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int> > result;
vector<int> sofar;
permutehelper(nums, sofar, result);
return result;
}
void permutehelper(vector<int> &rest, vector<int> &sofar, vector<vector<int>> &ans){
if(rest.size() == 0) {
ans.push_back(sofar);
}
else{
for(int i = 0; i < rest.size(); i++){
sofar.push_back(rest[i]);
rest.erase(rest.begin() + i);
permutehelper(rest, sofar, ans);
}
}
}
};
How do I modify it to return all permutation, Currently it is giving only [[1,2,3]]. I know there are many solutions but I want to make it work using vectors sofar and rest.
You only have one rest vector (and only one sofar vector) because you are passing by reference. That means that when you remove an element from rest, it's gone. You never put it back, so it's gone forever. (In fact, you're removing elements from the vector passed as an argument to permute. Some would say that modifying the argument is poor interface design.)
You probably want to pass the parameter vectors by value (other than ans, which accumulates results and thus should be permanently modified). Of course, passing by value makes copies, which introduces an unnecessary quadratic complexity, but it will allow the algorithm to work as expected.
To improve the readability, I'm trying to get out of the habit of reinventing the wheel.
Problem:
Consider a black-box function, Foo, which has an integer as input and output. We want to find the input that maximises the output. Consider that all the possible inputs belong to a single, contiguous range of integers; and that the range is small enough that we can try each one.
Speed is important, so we don't use containers. Even if the user has already created a container for all the possible inputs, it's still about 100x faster to calculate the next input (++input) than to get it from memory (cache misses).
Example:
Range: [5, 8)
Foo(5); // 19
Foo(6); // 72
Foo(7); // 31
We want to make a function that should return 6:
InputOfMaxOutputOnRange(5, 8, Foo); // 6
Custom solution:
template <typename T, typename Func>
T InputOfMaxOutputOnRange (T begin_range, T end_range, Func && Scorer)
{
// initialise:
auto max_o = Scorer(begin_range);
T i_of_max_o = begin_range;
// now consider the rest of the range:
++begin_range;
for (T i = begin_range; i < end_range; ++i)
{
auto output = Scorer(i);
if (max_o < output)
{
max_o = output;
i_of_max_o = i;
}
}
return i_of_max_o;
}
Question:
I use functions like this so often that I think there should be an STL way to do it. Is there?
C++20 ranges can do this:
template<typename T, typename F>
T argmax_iota(T begin, T end, F &&score) { // can't really think of a good name for this; maybe it doesn't even deserve its own function
return std::ranges::max(std::views::iota(begin, end), std::less{}, std::ref(score));
// over the values in the range [begin, end) produced by counting (iota)...
// find the one that produces the greatest value (max)...
// when passed to the projection function score...
// with those values under the ordering induced by std::less
}
Godbolt
iota does not store the whole range anywhere. Iterators into the range hold a single T value that is incremented when the iterator is incremented.
In general, the algorithms in the STL work on sequences of values, that are traversed by iterators. They tend to return iterators as well. That's the pattern that it uses.
If you're doing a lot of things like this, where your input "sequence" is a sequential list of numbers, then you're going to want an iterator that "iterates" over a sequence (w/o any storage behind it).
A little bit of searching turned up Boost.CountingIterator, which looks like it could do what you want. I'm confident that there are others like this as well.
Warning - completely untested code
auto iter = std::max_element(boost::counting_iterator<int>(5),
boost::counting_iterator<int>(8),
// a comparator that compares two elements
);
return *iter; // should be '6'
As others have observed, std::max_element is defined to get the largest element in a a range.
In your case, the "iterator" is an integer, and the result of dereferencing that iterator is...some result that isn't related to the input in an obvious (but apparently you have some way to getting it efficiently nonetheless).
This being the case, I'd probably define a specialized iterator class, and then use it with std::max_element:
#include <iostream>
#include <iterator>
#include <algorithm>
// your association function goes here. I've just done something
// where the relationship from input to output isn't necessarily
// immediately obvious
int association_function(int input) {
int a = input * 65537 + 17;
int b = a * a * a;
return b % 127;
}
class yourIterator {
int value;
public:
// create an iterator from an int value
explicit yourIterator(int value) : value(value) {}
// "Deference" the iterator (get the associated value)
int operator*() const { return association_function(value); }
// advance to the next value:
yourIterator operator++(int) {
yourIterator temp(value);
++value;
return temp;
}
yourIterator &operator++() {
++value;
return *this;
}
// compare to another iterator
bool operator==(yourIterator const& other) const { return value == other.value; }
bool operator!=(yourIterator const& other) const { return value != other.value; }
// get the index of the current iterator:
explicit operator int() const { return value; }
};
int main() {
// For demo, print out all the values in a particular range:
std::cout << "values in range: ";
std::copy(yourIterator(5), yourIterator(10), std::ostream_iterator<int>(std::cout, "\t"));
// Find the iterator that gives the largest value:
yourIterator max = std::max_element(yourIterator(5), yourIterator(10));
// print out the value and the index that gave it:
std::cout << "\nLargest element: " << *max << "\n";
std::cout << "index of largest element: " << static_cast<int>(max);
}
When I run this, I get output like this:
values in range: 64 90 105 60 33
Largest element: 105
index of largest element: 7
So, it seems to work correctly.
If you need to use this with a variety of different association functions, you'd probably want to pass that as a template parameter, to keep the iteration part decoupled from the association function.
// pass association as a template parameter
template <class Map>
class mappingIterator {
int value;
// create an instance of that type:
Map map;
public:
// use the instance to map from iterator to value:
int operator*() const { return map(value); }
Then you'd have to re-cast your association function into a form suitable for use as a template parameter, such as:
struct association_function {
int operator()(int input) const {
int a = input * 65537 + 17;
int b = a * a * a;
return b % 127;
}
};
Then in main you'd probably want to define a type for the iterator combined with an association function:
using It = mappingIterator<association_function>;
It max = std::max_element(It(5), It(10));
You can use std::max_element defined in <algorithm>.
This will return the iterator to the maximum element in a specified range. You can get the index using std::distance.
Example copied from cppreference.
std::vector<int> v{ 3, 1, -14, 1, 5, 9 };
std::vector<int>::iterator result;
result = std::max_element(v.begin(), v.end());
std::cout << "max element at: " << std::distance(v.begin(), result) << '\n';
I have a already-sorted vector called vec, and a target variable. The goal is to return the closest-to-target vector element.
I tried to use C++11 lambda function with [=] to capture outside variable
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vec{1,2,3,4,5};
double target = 3.14159;
int res = min(vec.begin(), vec.end(), [=](int v1, int v2) -> bool {
return abs(v1-target) < abs(v2-target);
});
cout << res << endl;
return 0;
}
I expect to get res=3, but it returns an error:
error: cannot convert 'const __gnu_cxx::__normal_iterator<int*, std::vector<int> >' to 'int' in initialization
You are using the wrong algorithm. std::min operates on two specific object passed as is, or on a std::initializer_list. For containers, use std::min_element instead. It returns an iterator, which needs to be dereferenced.
auto res = std::min_element(vec.cbegin(), vec.cend(), [=](int v1, int v2) -> bool {
return abs(v1-target) < abs(v2-target);
});
// Make sure that the range wasn't empty, i.e. res != vec.cend()...
const int min = *res;
Note that you might want to consider narrowing down the scope of your lambda closure by explicitly capturing the object that you need (in your case only one after all). And also consider passing .cbegin() and .cend() when you don't modify the container in question.
A solution that might potentially be more efficient and readable could use lower_bound to find the greater of two elements that could potentially be returned.
int custom_bound(std::vector<int> const& vec, double target) {
if (vec.empty()) {
// throw or make the function return `optional`, choose to taste
}
auto lb = std::lower_bound(vec.begin(), vec.end(), target);
if (lb == vec.end()) {
return *(lb - 1);
} else if (lb == vec.begin()) {
return *lb;
} else {
const int up = *lb;
const int down = *(lb - 1);
return std::abs(up-target) < std::abs(down-target) ? up : down;
}
}
Unfortunately this can't be easily done as a one-liner. It doesn't require any custom functors, though; it merely exploits the fact that the number must lie in between (inclusive) lower_bound and the iterator one before the LB.
We can make another observation that up will be equal or greater to target, while down can only be smaller. Hence the condition could be replaced with
up-target < target-down
which removes the need for std::abs.
So I have a map with a key as a string, and I want to sort that map by the first value in the strings.
I want to sort the strings like this:
10 - 20
40 - 50
60 - 80
200 - 400
420+
I have a couple of more maps that I sort alphabetically. But this doesn't work for this case, because it would sort on the first letter, so it will become:
10 - 20
200 - 400
40 - 50
60 - 80
420+
Which I obviously do not want.
I normally sort like this:
dropdowncategory.KeySort([](const string& A, const string& B) {
return A.Compare(B, ESearchCase::IgnoreCase) < 0;
});
Simple.
But in this case from the A and B I want to get the first number, convert it to int and sort on that.
So what I did is I wrote a function (Not able to test it yet, but it should get the first number from the string, this is not the problem.):
int GetIntFromString(string s) {
int value = 0;
string L, R;
if (s.Contains("-")) {
s.Split("-", &L, &R);
}
else{
s.Split("+", &L, &R);
}
value = FCString::Atoi(*L);
return value;
}
From this function I will get the first number in the string. Then I want to sort on that outcome.
What I tried is the following:
dropdowncategory.KeySort([](const string& A,const string& B) {
return GetIntFromString(A) < GetIntFromString(B);
});
and:
string SA, SB;
dropdowncategory.KeySort([SA,SB](string& A, string& B) {
return GetIntFromString(SA) < GetIntFromString(SB);
});
But I keep getting and error on the GetIntFromString function in the return value of the KeySort:
Error (active) an enclosing-function local variable cannot be referenced in a lambda body unless it is in the capture list.
I am not sure why though.
I guess I cannot use that function inside the KeySort because it is a local function, but I don't know how to fix that.
As stated in std::stoi documentation:
Discards any whitespace characters (as identified by calling isspace()) until the first non-whitespace character is found, then takes as many characters as possible to form a valid base-n (where n=base) integer number representation and converts them to an integer value.
(emphasis is mine) it does what you need already, so your lambda can be just:
dropdowncategory.KeySort([](const string& A,const string& B) {
return std::stoi(A) < std::stoi(B);
});
note, converting string to integer is not very simple operation so you may want to reorganize your data so you do not have to do it for that strings so many times.
You can try to express your intent: treat the entries as pairs of ints, and use existing sorting logic for that:
std::vector<std::tuple<int, int>> pairs;
std::transform(begin(dropdowncategory), end(dropdowncategory),
std::back_inserter(pairs),
[](auto s){
std::stringstream ss(s);
int i; ss >> i;
char dummy; ss >> dummy;
int j; ss >> j;
return std::make_tuple(i, j);
});
std::sort(begin(pairs), end(pairs)); // 30, 50 will come before 200, 210
// convert pairs back to strings?
FString SA, SB;
dropdowncategory.KeySort([SA,SB](FString& A, FString& B) {
return GetIntFromString(SA) < GetIntFromString(SB);
});
Here you have 2 local string vars, empty (I suppose, no idea what's FString). You provide a lambda as a sorting function. Usually such function should have signature bool(const Key& left, const Key& right), and your lambda almost satisfied this requirement (pay attention to const). left and right here will be two keys to compare, and you need to define this comparison to define your sorting order. So correct version would be:
dropdowncategory.KeySort([](const FString& A, const FString& B) {
return GetIntFromString(A) < GetIntFromString(B);
});
This still doesn't explain your error, mainly because I have no idea what the error is.
By the way, GetIntFromString should be a free function, or at least a static member function, because its implementation depends only on input parameters.
P.S. listen to #Slava in the question comments, which can lead to
dropdowncategory.KeySort([](const FString& A, const FString& B) {
return std::atoi(*A) < std::atoi(*B);
});
I need to check if two substrings are equal while inserting to a map. Here is the code:
class substring {
public:
substring(string* str, int offset, int length) : str(str), offset(offset), length(length) { }
bool operator < (const substring& val) const {
if (str->compare(offset, length, *val.str, val.offset, val.length) == 0) return false;
else return true;
}
int offset, length;
string* str;
};
This class above is a 'key' in my map. Lengths of both substrings are always same. Some of the conditions are wrong, cause it's still yelling 'invalid comparator'.
your if statement in comparation function code is convoluted way to say:
return str->compare(offset, length, *val.str, val.offset, val.length) != 0;
which is incorrect for comparison function that std::map requires. Remember you are implementing less than operator, not equivalence. If you want your substring to be sorted in ascending order use this:
return str->compare(offset, length, *val.str, val.offset, val.length) < 0;
I would recommend using const reference to std::string in you substring class - that will reflect the fact you do not accept nullptr as pointer and show intent that you do not want to change original string through this class and make your code cleaner.