I don't know why this two-liner works - c++

int countMatches(vector<vector<string>>& items, string ruleKey, string ruleValue) {
int idx = ruleKey == "type" ? 0 : ruleKey == "color" ? 1 : 2, res = 0;
return count_if(begin(items), end(items), [&](const auto &i) { return i[idx] == ruleValue; });
}
This is a problem off of leetcode. I attached the link below.
I will try and say what I think is going on, if anything is wrong - please correct me.
First, we are creating an int variable called idx. We assign it the current value of ruleKey (which is currently a string). If the string is "type", we assign idx the value of 0. If the string is "color", we assign idx the value of 1. If NEITHER of those two conditions pass, we assign idx the value of 2.
I don't know why res = 0 is even in the code, and I have no clue what is going on with the line of code that lies beneath. Especially with the [&](const auto &i) portion of the code.

I will try and say what I think is going on, if anything is wrong - please correct me.
Your understanding of the idx variable is correct.
I don't know why res = 0 is even in the code
It is simply declaring an unused variable res initialized to 0. Multiple variables of the same type can be declared in the same expression, eg:
int a = 0, b = 1;
In this case, yes res doesn't really belong and can safely be removed.
I have no clue what is going on with the line of code that lies beneath. Especially with the [&](const auto &i) portion of the code.
See the documentation for the std::count_if() algorithm and Lambda Expressions.
In a nutshell, std::count_if() loops through a range, calling a predicate for each element, and increments the result each time the predicate returns true. The code is using a lambda, ie an anonymous function type, for that predicate.
So, the code is iterating the items vector, counting how many of its inner vector elements have a value matching ruleValue at the index specified by idx. The code is basically equivalent to this:
int countMatches(vector<vector<string>>& items, string ruleKey, string ruleValue) {
int idx;
if (ruleKey == "type") idx = 0;
else if (ruleKey == "color") idx = 1;
else idx = 2;
int count = 0;
for(auto iter = items.begin(), end = items.end(); iter != end; ++iter) {
const auto &i = *iter;
if (i[idx] == ruleValue) ++count;
}
return count;
}

Related

Get the closest element to a given element in an std::set

I have a (sorted) set of unsigned int's. I need to find the closest element to a given number.
I am looking for a solution using the standard library,
my first solution was to use binary search, but STL's implementation only returns if the element exists.
This post, Find Closest Element in a Set, was helpful and I implemented a solution based on std::lower_bound method,
(*Assuming the set has more than 2 elements, no empty/boundary checks are made):
#include <iostream>
#include<set>
#include<algorithm>
#include<cmath>
int main()
{
std::set<unsigned int> mySet = {34, 256, 268, 500, 502, 444};
unsigned int searchedElement = 260;
unsigned int closestElement;
auto lower_bound = mySet.lower_bound(searchedElement);
if (lower_bound == mySet.end()){
closestElement = *(--lower_bound);
}
std::set<unsigned int>::iterator prevElement = --lower_bound;
bool isPrevClosest = std::abs(*prevElement - searchedElement) > std::abs(*lower_bound - searchedElement);
closestElement = isPrevClosest ? *prevElement : *lower_bound;
std::cout << closestElement << std::endl;
return 0;
}
Is there a simpler more standard solution?
I don't think there is a better solution than using .lower_bound. You can wrap your algorithm into a function template:
template<typename Set>
auto closest_element(Set& set, const typename Set::value_type& value)
-> decltype(set.begin())
{
const auto it = set.lower_bound(value);
if (it == set.begin())
return it;
const auto prev_it = std::prev(it);
return (it == set.end() || value - *prev_it <= *it - value) ? prev_it : it;
}
This function handles all corner cases (empty set, one element, first element, last element) correctly.
Example:
std::set<unsigned int> my_set{34, 256, 268, 500, 502, 444};
std::cout << *closest_element(my_set, 26); // Output: 34
std::cout << *closest_element(my_set, 260); // Output: 256
std::cout << *closest_element(my_set, 620); // Output: 502
Note that std::abs in your code does (almost) nothing: its argument has unsigned type and is always non-negative. But we know that std::set elements are ordered, hence we know that *prev_it <= value <= *it, and no std::abs() is needed.
You could use std::min_element() : as a comperator, give it a lambda that returns the absulute diff e.g.
std::min_element(mySet.begin(), mySet.end(), [searchedElement](const unsigned int a, const unsigned int b) {
return std::abs(searchedElement - a) < std::abs(searchedElement - b);
});
However, I do think this will no longer apply a binary search...
EDIT : Also, as stated in comments below, std::abs(x - y) for unsigned int values may return an unexpectedly large integer when x < y.
The std::set container is suitable for finding adjacent elements, i.e., finding the element that succeeds or precedes a given element. Considering the problem that you are facing:
I am looking for a solution using the standard library, my first solution was to use binary search, but STL's implementation only returns if the element exists.
There is still an approach you can follow without changing your logic: If the element – whose closest element you want to find – does not exist in the set, then you simply insert it in the set (it takes logarithmic time in the size of the set). Next, you find the closest element to this just added element. Finally, remove it from the set when you are done so that the set remains the same as before.
Of course, if the element was already in the set, nothing has to be inserted into or removed from the set. Therefore, you need to keep track of whether or not you added that element.
The following function is an example of the idea elaborated above:
#include <set>
unsigned int find_closest_element(std::set<unsigned int> s, unsigned int val) {
bool remove_elem = false;
auto it = s.find(val);
// does val exist in the set?
if (s.end() == it) {
// element does not exist in the set, insert it
s.insert(val);
it = s.find(val);
remove_elem = true;
}
// find previous and next element
auto prev_it = (it == s.begin()? s.end(): std::prev(it));
auto next_it = std::next(it);
// remove inserted element if applicable
if (remove_elem)
s.erase(it);
unsigned int d1, d2;
d1 = d2 = std::numeric_limits<unsigned int>::max();
if (prev_it != s.end())
d1 = val - *prev_it;
if (next_it != s.end())
d2 = *next_it - val;
return d1 <= d2? *prev_it: *next_it;
}

iterating vector of strings C++

The code is to read instructions from text file and print out graphic patterns. One is my function is not working properly. The function is to read the vectors of strings I've got from the file into structs.
Below is my output, and my second, third, and sixth graphs are wrong. It seems like the 2nd and 3rd vectors are not putting the correct row and column numbers; and the last one skipped "e" in the alphabetical order.
I tried to debug many times and still can't find the problem.
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>& , Pattern& );
int main()
{
for (int i = 0; i < command.size(); i++)
{
Pattern characters;
CommandProcessing(command[i], characters);
}
system("pause");
return 0;
}
void CommandProcessing(vector<string>& c1, Pattern& a1)
{
reverse(c1.begin(), c1.end());
string str=" ";
for (int j = 0; j < c1.size(); j++)
{
bool foundAlpha = find(c1.begin(), c1.end(), "alphabetical") != c1.end();
bool foundAll = find(c1.begin(), c1.end(), "all") != c1.end();
a1.isTriangular = find(c1.begin(), c1.end(), "triangular") != c1.end() ? true : false;
a1.isOuter = find(c1.begin(), c1.end(), "outer") != c1.end() ? true : false;
if (foundAlpha ==false && foundAll == false){
a1.token = '*';
}
//if (c1[0] == "go"){
else if (c1[j] == "rows"){
str = c1[++j];
a1.rowNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "columns"){
str = c1[++j];
a1.colNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "alphabetical")
a1.token = 0;
else if (c1[j] == "all"){
str = c1[--j];
a1.token = *str.c_str();
j++;
}
}
}
Before debugging (or posting) your code, you should try to make it cleaner. It contains many strange / unnecessary parts, making your code harder to understand (and resulting in the buggy behaviour you just described).
For example, you have an if in the beginning:
if (foundAlpha ==false && foundAll == false){
If there is no alpha and all command, this will be always true, for the entire length of your loop, and the other commands are all placed in else if statements. They won't be executed.
Because of this, in your second and third example, no commands will be read, except the isTriangular and isOuter flags.
Instead of a mixed structure like this, consider the following changes:
add a default constructor to your Pattern struct, initializing its members. For example if you initialize token to *, you can remove that if, and even the two bool variables required for it.
Do the parsing in one way, consistently - the easiest would be moving your triangular and outer bool to the same if structure as the others. (or if you really want to keep this find lookup, move them before the for loop - you only have to set them once!)
Do not modify your loop variable ever, it's an error magnet! Okay, there are some rare exceptions for this rule, but this is not one of them.
Instead of str = c1[++j];, and decrementing later, you could just write str = c1[j+1]
Also, are you sure you need that reverse? That makes your relative +/-1 indexing unclear. For example, the c1[j+1 is j-1 in the original command string.
About the last one: that's probably a bug in your outer printing code, which you didn't post.

Initializing An Array with a Variable Size

I am almost done with my code except I need help on two thing. Here is my code: Code. For the function below, I am trying to make it so that I can use the input of "n" to initialize my array, myBits, instead of a constant, which is currently 5.
My Other question is right below that. I am trying to switch all of the right most bits to "true". I wrote the for loop in "/* .....*/" but it doesn't seem to be working. Right above it, I do it long ways for C(5,4) ....(myBit[0] = myBit[1]....etc...... (I am using this to find r-combinations of strings).... and it seems to work. Any help would be appreciated!!
void nCombination(const vector<string> &Vect, int n, int r){
bool myBits[5] = { false }; // everything is false now
myBits[1] = myBits[2] = myBits[3] = myBits[4] = true;
/* for(int b = n - r - 1; b = n - 1; b++){
myBits[b] = true; // I am trying to set the r rightmost bits to true
}
*/
do // start combination generator
{
printVector(Vect, myBits, n);
} while (next_permutation(myBits, myBits + n)); // change the bit pattern
}
These are called variable length arrays (or VLAs for short) and they are not a feature of standard C++. This is because we already have arrays that can change their length how ever they want: std::vector. Use that instead of an array and it will work.
Use std::vector<bool>:
std::vector<bool> myBits(n, false);
Then you have to change your while statement:
while (next_permutation(myBits.begin(), myBits.end()));
You will also have to change your printVector function to take a vector<bool>& as the second argument (you won't need the last argument, n, since a vector knows its own size by utilizing the vector::size() function).
As to your program: If you're attempting to get the combination of n things taken r at a time, you will need to write a loop that initializes the last right r bools to true instead of hard-coding the rightmost 4 entries.
int count = 1;
for (size_t i = n-1; i >= 0 && count <= r; --i, ++count)
myBits[i] = true;
Also, you should return immediately from the function if r is 0.

Checking if reducing iterator points to a valid element

I need to know if I can reduce the iterator and have a valid object. The below errors out because I reduce the iterator by 1 which doesn't exist. How can I know that so I don't get the error?
ticks.push_front(Tick(Vec3(0, 0, 5), 0));
ticks.push_front(Tick(Vec3(0, 0, 8), 100));
ticks.push_front(Tick(Vec3(0, 0, 10), 200));
bool found = false;
list<Tick, allocator<Tick>>::iterator iter;
for (iter = ticks.begin(); iter != ticks.end(); ++iter)
{
Tick t = (*iter);
if (214>= t.timestamp)
{
prior = t;
if (--iter != ticks.end())
{
next = (*--iter);
found = true;
break;
}
}
}
I'm trying to find the entries directly "above" and directly "below" the value 214 in the list. If only 1 exists then I don't care. I need above and below to exist.
After your edits to the question, I think I can write a better answer than what I had before.
First, write a comparison function for Ticks that uses their timestamps:
bool CompareTicks(const Tick& l, const Tick& r)
{
return l.timestamp < r.timestamp;
}
Now use the function with std::upper_bound:
// Get an iterator pointing to the first element in ticks that is > 214
// I'm assuming the second parameter to Tick's ctor is the timestamp
auto itAbove = std::upper_bound(ticks.begin(), ticks.end(), Tick(Vec3(0, 0, 0), 214), CompareTicks);
if(itAbove == ticks.end())
; // there is nothing in ticks > 214. I don't know what you want to do in this case.
This will give you the first element in ticks that is > 214. Next, you can use lower_bound to find the first element that is >= 214:
// get an iterator pointing to the first element in ticks that is >= 214
// I'm assuming the second parameter to Tick's ctor is the timestamp
auto itBelow = std::lower_bound(ticks.begin(), ticks.end(), Tick(Vec3(0, 0, 0), 214), CompareTicks);
You have to do one extra step with itBelow now to get the first element before 214, taking care not to go past the beginning of the list:
if(itBelow == ticks.begin())
; // there is nothing in ticks < 214. I don't know what you want to do in this case.
else
--itBelow;
Now, assuming you didn't hit any of the error cases, itAbove is pointing to the first element > 214, and itBelow is pointing to the last element < 214.
This assumes your Ticks are in order by timestamp, which seems to be the case. Note also that this technique will work even if there are multiple 214s in the list. Finally, you said the list is short so it's not really worth worrying about time complexity, but this technique could get you logarithmic performance if you also replaced the list with a vector, as opposed to linear for iterative approaches.
The answer to your core question is simple. Don't increment if you are at the end. Don't decrement if you are at the start.
Before incrementing, check.
if ( iter == ticks.end() )
Before decrementig, check.
if ( iter == ticks.begin() )
Your particular example
Looking at what you are trying to accomplish, I suspect you meant to use:
if (iter != ticks.begin())
instead of
if (--iter != ticks.end())
Update
It seems you are relying on the contents of your list being sorted by timestamp.
After your comment, I think what you need is:
if (214>= t.timestamp)
{
prior = t;
if (++iter != ticks.end())
{
next = *iter;
if ( 214 <= next.timestep )
{
found = true;
break;
}
}
}
Update 2
I agree with the comment made by #crashmstr. Your logic can be:
if (214 <= t.timestamp)
{
next = t;
if ( iter != ticks.begin())
{
prior = *--(iter);
found = true;
break;
}
}
I think you can do what you want with std::adjacent_find from the standard library <algorithm>. By default std::adjacent_find looks for two consecutive identical elements but you can provide your own function to define the relationship you are interested in.
Here's a simplified example:
#include <algorithm>
#include <iostream>
#include <list>
struct matcher
{
matcher(int value) : target(value) {}
bool operator()(int lo, int hi) const {
return (lo < target) && (target < hi);
}
int target;
};
int main()
{
std::list<int> ticks = { 0, 100, 200, 300 };
auto it = std::adjacent_find(ticks.begin(), ticks.end(), matcher(214));
if (it != ticks.end()) {
std::cout << *it << ' ' << *std::next(it) << '\n';
} else {
std::cout << "not found\n";
}
}
This outputs 200 300, the two "surrounding" values it found.

Reversing for loop causing system errors

This feels like a newbie issue, but I can't seem to figure it out. I want to iterate over the items in a std::vector. Currently I use this loop:
for (unsigned int i = 0; i < buffer.size(); i++) {
myclass* var = buffer.at(i);
[...]
}
However, I realised that I actually want to iterate over it in the opposite order: starting at the end and working my way to 0. So I tried using this iterator:
for (unsigned int i = buffer.size()-1; i >= 0; i--) {
myclass* var = buffer.at(i);
[...]
}
But by simply replacing the old line with the new (and of course, recompiling), then it goes from running properly and iterating over the code, it instead causes the program to crash the first time it hits this line, with this error:
http://i43.tinypic.com/20sinlw.png
Followed by a "[Program] has stopped working" dialog box.
The program also returns exit code 3, according to Code::Blocks, which (if this article is to be believed) means ERROR_PATH_NOT_FOUND: The system cannot find the file specified.
Any advice? Am I just missing something in my for loop that's maybe causing some sort of memory issue? Is the return code of 3, or the article, misleading, and it doesn't actually mean "path not found"?
An unsigned integer is always >= 0. Furthermore, decrementing from 0 leaps to a large number.
When i == 0 (i.e. what should be the last iteration), the decrement i-- causes i to wrap around to the largest possible value for an unsigned int. Thus, the condition i >= 0 still holds, even though you'd like the loop to stop.
To fix this, you can try something like this, which maintains the original loop logic, but yields a decrementing i:
unsigned int i;
unsigned int size = buffer.size();
for (unsigned int j = 0; j < size; j++) {
i = size - j - 1;
Alternatively, since std::vector has rbegin and rend methods defined, you can use iterators:
for(typename std::vector<myclass *>::reverse_iterator i = buffer.rbegin(); i != rend(); ++i)
{
myclass* var = *i;
// ...
}
(There might be small syntactic errors - I don't have a compiler handy)
#include <vector>
using namespace std;
int main() {
vector<int> buffer = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (vector<int>::reverse_iterator it = buffer.rbegin(); it != buffer.rend(); it++) {
//do your stuff
}
return 0;
}