I want to apply a condition using higher-order infix extension function on a list of pair.
I want my condition to show me the first numbers of the pair. Specifically, show those first numbers whose sum with their second number is 5.
T
this is the code I have written so far
fun main() {
infix fun List<Pair<Int,Int>>.takeFirstsBy(
condition: // i need help in this line to apply a condition on list of pair
):List<Int>{
}
}
I don't know how to write a conditional statement to apply to pairs after the (condition) statement
please help me. Thanks
There's no reason to make a higher order function infix, because of trailing lambda syntax. All it would do is allow you to replace the dot with a space, and make the code harder to read because it differs from conventional syntax. Also, higher order functions on collections are often chained from line to line, and you can only do this by using dot notation.
It would make sense to make it inline though, so the lambda doesn't have to be allocated each time you call this function.
You can make the receiver type an Iterable to make the function more versatile.
Your conditional has an input of a Pair of Ints, and needs to return a Boolean, so the signature is (Pair<Int, Int>) -> Boolean.
The logic of your function is to filter to only the ones that pass the condition, and then to map that filtered result to show only the first number of the pair.
inline fun Iterable<Pair<Int,Int>>.takeFirstsBy(
condition: (Pair<Int,Int>)->Boolean
):List<Int>{
return filter(condition).map { it.first }
}
fun main() {
val input = listOf(1 to 4, 2 to 3, 5 to 5)
val result = input.takeFirstsBy { it.first + it.second == 5 }
println(result)
}
Alternate implementation. I think this is less readable, but it is more efficient:
inline fun Iterable<Pair<Int,Int>>.takeFirstsBy(
condition: (Pair<Int,Int>)->Boolean
):List<Int>{
return mapNotNull { it.takeIf(condition)?.first }
}
You don't write the condition but the invoker does.
condition: (Pair<Int, Int>) -> Boolean
We need an argument Pair<Int, Int> because is the item of the list, so you call it on the iterator you use.
infix fun List<Pair<Int,Int>>.takeFirstsBy(
condition: (Pair<Int, Int>) -> Boolean
):List<Int>{
return this.mapNotNull {
if (condition.invoke(it)) {
//pair.first or pair.second ?
} else null //null won't be included
}
}
And then you call it like this
So the iterator runs through the list and filter the thing on the condition
list.takeFirstBy { pair: Pair<Int, Int> ->
//implement the condition here, returning true/false
}
Related
I'm working on my own blockchain implementation in C++17.
To learn as much as possible, I would like to reduce loops as least as possible, moving to the alternative (and more expressive) loops within the std::algorithm library.
In a nullshell, within the Blockchain algorithm, each block contains it's own hash and the hash of the previous block (except the Genesis-Block which doesn't contain a previous block [first in the container]).
I want to implement a Validate function in the Blockchain object that takes pairs of blocks (which are contained in a std::vector), and checks the hashes (and previous hashes) to make sure they haven't been tampered with.
Current code (works):
bool Blockchain::Validate() const
{
// HASH is in ASCII
std::array<unsigned char, 64> calculated_hash{};
// No underflow here since Genesis-Block is created in the CTOR
for (auto index = this->chain_.size() - 1; index > 0; --index)
{
const auto& current_block{this->chain_[index]};
const auto& previous_block{this->chain_[index - 1]};
SHA256{previous_block}.FillHash(calculated_hash);
if (!std::equal(std::begin(calculated_hash), std::end(calculated_hash),
std::begin(current_block.GetPreviousHash()), std::end(current_block.GetPreviousHash())))
{
return false;
}
}
return true;
}
I would like to know if there's an algorithm that works somehow the way Python does its ", ".join(arr) for strings, which appends commas between each adjacent pair in the array, but instead will check until a certain condition returns false in which case stops running.
TLDR:
If this is my container:
A B C D E F G
I would like to know if theres an algorithm that asserts a condition in adjacent pairs: (A, B), (B, C), (C, D), (D, E), (E, F), (F, G)
And will stop if a condition has failed, for example:
A with B -> True
B with C -> True
C with D -> False
So the algorithm will return false. (Sounds like an adjacent implementation of std::all_of).
Does a std::algorithm like this exist? Thanks!
If you have some range v where you want to check each adjacent element for some condition, and return early, you can use std::adjacent_find.
First write a lambda that compares adjacent elements:
auto comp = [](auto left, auto right)
{
return // the Negation of the actual condition
}
Note that the negation is needed, so that you return early when you reach the actual false case. So in your case, A,B and B,C would compare false, and C,D would compare true.
Now you can use the lambda like this:
return std::adjacent_find(std::begin(v), std::end(v), comp) == std::end(v);
In your manual loop, you actually appear to be iterating in reverse, in which case you can write:
return std::adjacent_find(std::rbegin(v), std::rend(v), comp) == std::rend(v);
Full disclosure, this may be a hammer and nail situation trying to use STL algorithms when none are needed. I have seen a reappearing pattern in some C++14 code I am working with. We have a container that we iterate through, and if the current element matches some condition, then we copy one of the elements fields to another container.
The pattern is something like:
for (auto it = std::begin(foo); it!=std::end(foo); ++it){
auto x = it->Some_member;
// Note, the check usually uses the field would add to the new container.
if(f(x) && g(x)){
bar.emplace_back(x);
}
}
The idea is almost an accumulate where the function being applied does not always return a value. I can only think of a solutions that either
Require a function for accessing the member your want to accumulate and another function for checking the condition. i.e How to combine std::copy_if and std::transform?
Are worse then the thing I want to replace.
Is this even a good idea?
A quite general solution to your issue would be the following (working example):
#include <iostream>
#include <vector>
using namespace std;
template<typename It, typename MemberType, typename Cond, typename Do>
void process_filtered(It begin, It end, MemberType iterator_traits<It>::value_type::*ptr, Cond condition, Do process)
{
for(It it = begin; it != end; ++it)
{
if(condition((*it).*ptr))
{
process((*it).*ptr);
}
}
}
struct Data
{
int x;
int y;
};
int main()
{
// thanks to iterator_traits, vector could also be an array;
// kudos to #Yakk-AdamNevraumont
vector<Data> lines{{1,2},{4,3},{5,6}};
// filter even numbers from Data::x and output them
process_filtered(std::begin(lines), std::end(lines), &Data::x, [](int n){return n % 2 == 0;}, [](int n){cout << n;});
// output is 4, the only x value that is even
return 0;
}
It does not use STL, that is right, but you merely pass an iterator pair, the member to lookup and two lambdas/functions to it that will first filter and second use the filtered output, respectively.
I like your general solutions but here you do not need to have a lambda that extracts the corresponding attribute.
Clearly, the code can be refined to work with const_iterator but for a general idea, I think, it should be helpful. You could also extend it to have a member function that returns a member attribute instead of a direct member attribute pointer, if you'd like to use this method for encapsulated classes.
Sure. There are a bunch of approaches.
Find a library with transform_if, like boost.
Find a library with transform_range, which takes a transformation and range or container and returns a range with the value transformed. Compose this with copy_if.
Find a library with filter_range like the above. Now, use std::transform with your filtered range.
Find one with both, and compose filtering and transforming in the appropriate order. Now your problem is just copying (std::copy or whatever).
Write your own back-inserter wrapper that transforms while inserting. Use that with std::copy_if.
Write your own range adapters, like 2 3 and/or 4.
Write transform_if.
I want to know how I can look up for an item in a map using a regex function. In my case, I have a map with expressions such as en*, es*, en-AU and so on and I have a string of possible values like en, en-US, en-GB, es-CL and so on.
I want to search using that string to find that item in the map.
Looking for the key without the wildcard first then looking for the key with the wildcard as the 2nd priority.
Please help me out with this problem or if this is an inefficient or if any one has a different approach please tell me another method for that. I use C++ with boost and stl.
If the map is small or the search is executed rarely, then just iterate through the map and match each key with the regular expression.
Otherwise: If the regular expression is used only for some kind of prefix search, you can use the member function lower_bound to efficiently find all entries with the given prefix. For example the following function first looks for an entry that matches exactly. If no such entry exists, the function returns the range of all entries with a matching prefix.
using items = std::map<std::string, item>;
auto lookup(const items& items, const std::string& key)
-> std::pair<items::const_iterator, items::const_iterator>
{
auto p = items.lower_bound(key);
auto q = items.end();
if (p != q && p->first == key) {
return std::make_pair(p, std::next(p));
} else {
auto r = p;
while (r != q && r->first.compare(0, key.size(), key) == 0) {
++r;
}
return std::make_pair(p, r);
}
}
Otherwise: If you have to cope with regular expressions or wildcards, then you can combine the two approaches. First search for an entry that matches exactly with the member function find. If no such entry exists, then extract the constant prefix from the regular expression. The prefix may be empty. Use the member function lower_bound to find the first entry with that prefix. Iterate through all entries with that prefix and test if the regular expression matches.
Given a container of boolean values (An example is std::vector<bool>), is there a standard function that returns true if all the values are true ("and") or true if at least one value is true ("or"), with short circuit evalutation ?
I digged trough www.cplusplus.com this morning but couldn't find anything close.
is there a standard function that returns true if all the values are true ("and")
std::all_of(vec.begin(), vec.end(), [](bool x) { return x; } )
or true if at least one value is true ("or")
std::any_of(vec.begin(), vec.end(), [](bool x) { return x; } )
with short circuit evalutation?
I just inserted print statements into the lambda, and yes, both functions perform short-circuiting.
You can implement by:
AND:
std::find(vector.begin(), vector.end(), false) == vector.end() // all the values are true
OR:
std::find(vector.begin(), vector.end(), true) != vector.end() //at least one value is true
You can use the function objects logical_and and logical_or in conjunction with a reduction to accomplish that.
accumulate calculates the reduction. Hence:
bool any = std::accumulate(foo.begin(), foo.end(), false, std::logical_or<>());
bool all = std::accumulate(foo.begin(), foo.end(), true, std::logical_and<>());
Caveat: this is not using short-circuiting (the accumulate function knows nothing about short-circuiting even though the functors do), while Igor’s clever solution is.
If you do not need a generic algorithm for different container types...
As you are looking for short circuit evaluation, you may give std::valarray a chance. For and use valarray::min() == true for or you could use std::find as mentioned by Igor.
In case you know the number of elements to store at compile time, you could even use a std::bitset:
bitset<100> container();
//... fill bitset
bool or = container.any();
bool and = container.count() == container.size();
While using std::for_each algorithm how do I break when a certain condition is satisfied?
You can use std::any_of (or std::all_of or std::none_of) e.g. like this:
std::vector<int> a;
// ...
std::all_of(a.begin(), a.end(), [&](int val) {
// return false if you want to break, true otherwise
});
However, this is a wasteful solution (return values are not really used for anything), and you're better off writing you own loop.
You can use std::find_if algorithm, which will stop and return the iterator to the first element where the predicate condition applied to returns true. So your predicate should be changed to return a boolean as the continue/break condition.
However, this is a hack, so you can use the algorithms.
Another way is to use BOOST_FOREACH.
You can break from the for_each() by throwing an exception from your functor. This is often not a good idea however, and there are alternatives.
You can retain state in your functor. If you detect the 'break' condition, simply set a flag in your functor and then for each subsequent iteration simply return without doing your functor's thing. Obviously this won't stop the iteration, which might be expensive for large collections, but it will at least stop the work from being performed.
If your collection is sorted, you can find() the element that you want to break at, then do for_each from begin() to the element find() returned.
Finally, you can implement a for_each_if(). This will again not stop the iteration but will not evaluate your functor which does the work if the predicate evaluates to false. Here are 2 flavors of for_each_xxx(), one which takes a value and performs the work if operator==() evaluates to true, and another which takes two functors; one which performs a comparison ala find_if(), and the other which performs the work if the comparison operator evaluates to true.
/* ---
For each
25.1.1
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)
Requires:
T is of type EqualityComparable (20.1.1)
Effects:
Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:
1: *i == value
2: pred(*i) != false
Returns:
f
Complexity:
At most last - first applications of f
--- */
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first,
InputIterator last,
Predicate pred,
Function f)
{
for( ; first != last; ++first)
{
if( pred(*first) )
f(*first);
}
return f;
};
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first,
InputIterator last,
const T& value,
Function f)
{
for( ; first != last; ++first)
{
if( *first == value )
f(*first);
}
return f;
};
If you want do some actions while condition is not satisfied, maybe you need change algorithm on something like std::find_if?
As already shown by others it is only achievable with workarounds that IMHO obfuscate the code.
So my suggestions is to change the for_each into a regular for loop. This will make it more visible to others that you are using break (and maybe even continue).
You can't do it, unless you throw an exception, which is not a good idea because you don't do flow control with exceptions.
Update: apparently Boost has a for_each_if that might help, but you're not using Boost.
You throw an exception. Whether or not it's a good idea is sort of a style question, pace #Dan, but may be more of an issue with your design. for_each is intended for a sort of functional-programming style, which implicitly assumes that your function can be applied uniformly across the set. So, if you do need to break, that could be consiered an unusual condition, and therefore worthy of an exception.
The other solution, and a more "functional" solution, is to write your function so that if it shouldn't have an effect on some applications, then write it to have no effect. So, for example, if you had a summing function, have it add 0 in the cases you would have "broken" from.
You can use std::find_if instead std::for_each:
int aaa[]{ 1, 2, 3, 4, 5, 6, 7, 8 };
std::find_if(aaa, std::next(aaa, sizeof(aaa) / sizeof(int)), [](const auto &i) {
if (i == 5)
return true;
std::cout << i << std::endl;
return false;
});
Output:
1
2
3
4