有效的方法来查找std :: vector中每个唯一值的频率

时间:2013-12-28 23:55:45

标签: c++ c++11 vector stl unique

给定一个向量std::vector<double> v,我们可以通过以下方式有效地找到唯一元素:

std::vector<double> uv(v.begin(), v.end());
std::sort(uv.begin(), uv.end());
std::erase(std::unique(uv.begin, uv.end()), uv.end());

创建矢量是最好的方式(没有循环,使用STL或lambdas):

std::vector<double> freq_uv(uv.size());

包含v中出现的每个不同元素的频率(与排序的唯一值的顺序相同)?

注意:类型可以是任何内容,而不仅仅是double

4 个答案:

答案 0 :(得分:5)

排序后,在删除之前:

std::vector<int> freq_uv;
freq_uv.push_back(0);
auto prev = uv[0];        // you should ensure !uv.empty() if previous code did not already ensure it.
for (auto const & x : uv)
{
    if (prev != x)
    {
        freq_uv.push_back(0);
        prev = x;
    }
    ++freq_uv.back();
}

请注意,虽然我通常喜欢使用地图计算出现次数,但正如Yakk所做的那样,在这种情况下,我认为它正在进行大量不必要的工作,因为我们已经知道向量已经排序。

另一种可能性是使用std::map(非无序),代替进行排序。这将首先获得您的频率。然后,由于地图是有序的,您可以直接从地图创建排序的唯一向量和频率向量。

// uv not yet created
std::map<T, int> freq_map;
for (auto const & x : v)
    ++freq_map[x];
std::vector<T> uv;
std::vector<int> freq_uv;
for (auto const & p : freq_map)
{
    uv.push_back(p.first);
    freq_uv.push_back(p.second);
}

答案 1 :(得分:3)

首先,请注意== <以及double double上的template<typename T, typename Allocator> std::unordered_map< T, std::size_t > frequencies( std::vector<T, Allocator> const& src ) { std::unordered_map< T, std::size_t > retval; for (auto&& x:src) ++retval[x]; return retval; } 通常是一个糟糕的主意:如果{{{}},那么通常你会有逻辑“应该”相等的值{1}}是无限精度,但略有不同。

但是,收集频率很容易:

std::hash<T>

假设double已定义(适用于vector)。如果没有,那就有更多样板,所以我会跳过它。请注意,这并不关心std::vector<std::size_t>是否已排序。

如果您想以vector的形式与已排序的template<typename T, typename Hash, typename Equality, typename Allocator> std::vector<std::size_t> collate_frequencies( std::vector<T, Allocator> const& order, std::unordered_map<T, std::size_t, Hash, Equality> const& frequencies ) { std::vector<std::size_t> retval; retval.reserve(order.size()); for( auto&& x : order ) retval.push_back( frequencies[x] ); return retval; } 同步,则可以执行以下操作:

double

我冒昧地使这些功能过于通用,因此他们支持的不仅仅是{{1}}。

答案 2 :(得分:0)

使用equal_range

std::vector<int> results;
for(auto i = begin(v); i != end(v);)
{
    auto r = std::equal_range(i, end(v), *i);
    results.emplace_back( std::distance(r.first, r.second) );
    i = r.second;
}

SSCCE:

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    std::vector<double> v{1.0, 2.0, 1.0, 2.0, 1.0, 3.0};
    std::sort(begin(v), end(v));

    std::vector<int> results;
    for(auto i = begin(v); i != end(v);)
    {
        auto r = std::equal_range(i, end(v), *i);
        results.emplace_back( std::distance(r.first, r.second) );
        i = r.second;
    }

    for(auto const& e : results) std::cout << e << "; ";
}

答案 3 :(得分:0)

当值的范围受到限制时的O(n)解决方案,例如chars。为计数器使用少于CPU 1级缓存的空间将为其他值留出空间。

(未经测试的代码)

constexp int ProblemSize = 256;
using CountArray = std::array<int, ProblemSize>;

CountArray CountUnique(const std::vector<char>& vec) {
  CountArray count;
  for(const auto ch : vec)
    count[ch]++;

  return count;
}