应用函数后查找重复值的函数
Function to find duplicate values after applying a function
我想要一个C++函数,该函数在集合中查找与集合中另一个项目具有相同值function(key)
的项目。
例如
std::set<int> ints = {1, -1, 3};
// Finds an item in the set with the same absolute value as
// another item.
int* dupe = find_duplicates(ints, [](int x) { return std::abs(x); });
// Should print -1 or 1
if (dupe != 0) std::cout << "Found dupe: " << *dupe << std::endl;
但是,我什至无法为此方法编写函数签名。
在Java中,它会像static Integer findDuplicates<T, U>(Iterable<T>, Function<T, U> func)
。在C++中,我已经了解了以下内容,但它无法编译:
template<template <typename T> Collection, typename U>
T* find_duplicates(
const Collection<T>& collection,
const std::function<U(T)>& func) { ... }
我得到的错误是error: 'T' does not name a type
.
有什么指示吗?(我也对一种绕过使用指向T*
的"原始"指针的方法感兴趣,但对于单独的问题来说,这可能更好(
在您的示例中,T
无法识别且几乎无用。您应该更早地介绍类型T
,然后使用它来指定Collection
,如下所示:
template<typename T, template <typename> typename Collection, typename U>
T* find_duplicates(const Collection<T>& collection,
const std::function<U(T)>& func)
{
// some logic here
}
另外:请注意,正如我之前在评论中指出的那样,您在Collection
之前错过了一次typename
。上面的示例针对该建议进行了调整。
对于您的特定示例,这样的事情应该有效,
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main() {
std::set<int> ints = {1, -1, 3};
auto dupe = std::find_if(ints.begin(),ints.end(),[&](const int& first){
return std::find_if(ints.begin(),ints.end(),[&](const int& second) {
// so a the same value isn't checked against itself..
if (&first == &second) return false;
return std::abs(first) == std::abs(second);
}) != ints.end();
} );
if (dupe != ints.end()) std::cout << "Found dupe: " << *dupe << std::endl;
}
演示
不要对函数参数类型太挑剔。 你真的不需要collection
成为类模板专用化,只需要你可以迭代的东西(甚至可以是 C 风格的数组(。func
只需要是可调用的,并且强制它成为std::function
对象可能比直接使用函数指针或 lambda 效率低,因为std::function
添加然后解析的类型擦除。
因此,工作声明可能是
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*;
我会做的:
#include <utility>
#include <iterator>
#include <set>
// Calling with an rvalue collection would be bad news.
template <typename Collection, typename Func>
void find_duplicates(Collection&&, const Func&) = delete;
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*
{
auto iter = std::begin(collection);
using value_type = typename std::iterator_traits<decltype(iter)>::value_type;
auto ptr_compare = [&func](value_type* p, value_type* q)
{ return func(*p) < func(*q); };
std::set<value_type*, decltype(ptr_compare)> iter_set{ptr_compare};
for (; iter != std::end(collection); ++iter) {
auto insert_result = iter_set.insert(std::addressof(*iter));
if (!insert_result.second)
return *insert_result.first;
}
return nullptr;
}
有时,原始指针确实是答案。这意味着该值可能为 null,并且指针与对象没有所有权关系。在这种情况下,在指针通过修改或销毁容器使其失效后不使用指针取决于调用方,但它具有通常的指向容器元素失效语义,具体取决于容器详细信息。
这不适用于std::vector<bool>
或*collection.begin()
具有"代理"类型的任何其他伪容器。 如果要支持这些并且可以使用 C++17std::optional
或boost::optional
,则可以返回optional<value_type>
而不是原始指针,尽管这将复制返回的重复值。 如果你不能使用这些或副本是不需要的,也许可以编写一个模板类iter_or_null<InputIter>
包含一个迭代器,具有只调用迭代器的运算符的operator*
和operator->
,并满足NullablePointer
概念。
你实际上对你的模板过于严格。您希望模板采用定义了 std::begin 和 std::end 的任何容器,以及可以接受容器包含的任何内容的实例的任何函数对象。在模板世界中,你只接受任何类型,按照你想要的方式使用它,如果调用方没有提供兼容类型的对象,他们将得到编译错误。
此外,没有必要使用 std::function - 当你只接受函数对象作为具有推导类型的参数时,它最终可能会分配内存。
使用 C++14,自动推导的返回类型和 lambda 的自动参数允许您编写非常通用的代码。这是我的解决方案。它将迭代器返回到容器中,指向找到的第一个重复项,如果未找到重复项,则返回 std::end(c(。
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iostream>
#include <set>
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func)
{
return std::find_if(std::begin(c), std::end(c), [&](const auto & first) {
return std::any_of(std::begin(c), std::end(c), [&](const auto & second) {
return &first != &second && func(first) == func(second);
});
});
}
int main()
{
std::set<int> s{1, 3, -1};
auto const iter = find_duplicates(s, [](int x) { return std::abs(x); });
if (iter != std::end(s))
{
std::cout << "Duplicate found: " << *iter << 'n';
}
}
编辑:我刚刚注意到您指定了C++11标签。在 C++11 中,它只是稍微复杂一点:
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func) -> decltype(std::begin(c))
{
using ContainedType = decltype(*std::begin(c));
return std::find_if(std::begin(c), std::end(c), [&](const ContainedType & first) {
return std::any_of(std::begin(c), std::end(c), [&](const ContainedType & second) {
return &first != &second && func(first) == func(second);
});
});
}
- 使用.find函数在c++中查找字符和另一个字符之间的大小
- 一个函数,用于查找字符串1包含字符串2 c++的次数
- 用于在 C++ 中使用 while 循环查找下一个素数的简单函数
- C++ 函数,用于查找传入的 N 个数字的平均值、总和、最小值和最大值
- 使用用户定义的函数查找数字的幂时出现问题
- 如何处理具有不同类的成员函数的函数查找表?
- 如果我们没有在 C++ 中传递大小变量,则通过函数查找数组的大小
- 使用用户定义的函数查找完美数时出现浮点异常错误
- 使用 lambda 函数查找 std::unordered_map 中的最小值
- 重载函数查找轮廓的实例与参数列表不匹配
- 使用C++中的割线函数查找根
- JNA 程序函数查找失败
- 通过 C 加加号中的函数查找中位数
- 试图通过函数查找数组的最大值和最小值,其中数组值由用户输入
- xlC模板函数问题的静态函数查找
- 使用线程函数查找 2D 数组中的最大条目
- 如何在cpp中使用std::regex_replace()函数查找和替换
- 数组函数查找最大值
- 使用' stdio.h '函数查找模板和名称
- CPP字符串构造函数查找并附加空字符