计算独特项目的更好方法

Posted

技术标签:

【中文标题】计算独特项目的更好方法【英文标题】:better way of counting unique item 【发布时间】:2015-01-22 23:45:43 【问题描述】:

我只是找到了一种方法来计算向量中唯一项目的数量。这是我最幼稚的做法。

std::vector<Items> v;

// some other work
std::vector<Items> unique_Count;
unique_Count.clear();
std::unique_copy(v.begin, v.end(), std::back_inserter(unique_Count);
int uniqueCount = unique_Count.size();

这是标准库中唯一的方法还是有更好的方法?

【问题讨论】:

你不能使用 std::set (ordered) 或 unordered_set - cplusplus.com/reference/set/set吗?地图也有用吗?在 Java 和 C++ 中非常标准。获得元素集后,您可以比较大小并找出 1) 有多少元素是重复的 2) 哪些元素是重复的。 对于 OP,集合不会创建重复项,因此仅包含唯一项。 @chris True,但这完全是为了找到一种“机制”来使用 C++ STL 进行唯一元素计数,并且 OP 可以编写他/她自己的方法。 unique_copy 方法仅在您先对向量进行排序时才有效。但是使用集合要容易得多。 虽然使用set 可能会让你看起来很酷的代码只占用几行代码,但sort + unique(或unique_copy)很有可能在vector 上由于更好的spatial locality,您可以获得更好的性能,特别是对于移动便宜的类型。如果您关心这些事情,请衡量这两种方法的性能并自行决定。 【参考方案1】:

这取决于您所说的“更好”是什么意思,但肯定有更简单的方法,而其他方法可能更快。

真正简单的方法是将项目插入std::setstd::unordered_set。当您插入所有这些时,集合的大小将是唯一项目的数量。

可能更快的方法是使用std::sortstd::unique 来“就地”找到独特的项目,而不是复制它们。这相当std::unique_copy 通常在内部会做的事情,但是在适当的地方做这件事可以节省相当多的分配和复制。

std::vector<Items> v;

// populate v with data

std::sort(v.begin(), v.end());
int uniqueCount = std::unique(v.begin(), v.end()) - v.begin();

【讨论】:

std::unique 返回唯一范围的结尾,而开始未修改。结果表达式应改为int uniqueCount = std::unique(v.begin(), v.end()) - v.begin() 我不想至少在最初对向量进行排序,而只想计算向量中唯一项目的数量 @user4425844:我猜想计算唯一项目的问题无法比排序更快地解决(使用基于比较的方法时)。所以排序不应该被拒绝。【参考方案2】:
struct iterator_hash 
  template<class Iterator>
  size_t operator()(Iterator it) const 
    using value_type = typename std::decay< decltype(*it) >::type;
    return std::hash<value_type>( *it );
  
;
struct iterator_element_equals 
  template<class Iterator>
  size_t operator()(Iterator lhs, Iterator rhs) const 
    return *lhs == *rhs;
  
;
std::vector<Items> v;
std::unordered_set<std::vector<Items>::iterator, iterator_hash, iterator_element_equals> s;
for(auto it = v.begin(); it != v.end(); ++it) 
  s.insert(it); // not *it

size_t uniqueCount = s.size();

在这里,我在向量迭代器上创建一个散列,对底层元素进行散列和比较(不要将.end() 迭代器传递给它)。

然后我将集合中的迭代器插入其中,并询问它有多大。

如果您愿意,我们可以改用 std::set&lt;Iterator, iterator_less&gt; 或其他名称。

【讨论】:

【参考方案3】:

我看到这篇文章的最后一个答案是大约 6 年前。我一直在寻找解决方案,因为我最近在我一直从事的一个项目中遇到了这个问题,我想分享我的解决方案。我认为这是一种更现代的模板化解决方案,可以用作黑匣子,或者这样,用于存储在std::vector 容器中的数据。

假设你在头文件uniques.hpp中有以下代码

#ifndef UNIQUES_HPP
#define UNIQUES_HPP

#include <algorithm>
#include <vector>

template<typename T>
std::vector<T> unique_values( std::vector<T> & input_vec )

    std::vector<T> uniques( input_vec.size() );
    typename std::vector<T>::iterator it;
    it = std::unique_copy (input_vec.begin(), input_vec.end(), uniques.begin() );

    std::sort( uniques.begin(), it );

    it = std::unique_copy( uniques.begin(), it, uniques.begin() );

    uniques.resize( std::distance(uniques.begin(), it) );

    return uniques;


template<typename T>
std::vector<int> count_unique_values( std::vector<T> & input_vec )

    std::vector<T> uniques = unique_values<T>( input_vec );
    std::vector<int> counts( uniques.size() );

    for(size_t i = 0; i < counts.size(); ++i)
        counts[i] = std::count( input_vec.begin(), input_vec.end(), uniques[i] );

    return counts;


#endif

使用unique_values 上方头文件中出现的第一个函数,可以在整数、浮点数甚至字符串的向量中找到唯一值。除此之外,我还有第二个函数count_unique_values,它返回每个唯一值的出现次数。

下面我展示了存储在向量中的intfloatstd::string 数据的三个示例。

#include <iostream>
#include <vector>
#include <string>

#include "uniques.hpp"

template<typename T>
std::ostream & operator<<(std::ostream & o, const std::vector<T> & v)
    
    o << "[ ";
    for (size_t i = 0; i < v.size()-1; i++)
        o << v[i] << ", ";

    o << v[v.size()-1];

    std::cout << " ]" << std::endl;
    
    return o;


int main()

// Example with integers
    std::cout << "Example with integers" << std::endl;
    std::cout << "---------------------" << std::endl;
    
    std::vector<int> v_init_int = 1,5,5,1,1,1,3,5,4,3,3,3,0;
    std::cout << "Initial vector: " << v_init_int;
    
    std::vector<int> v_uniques_int = unique_values<int>( v_init_int );
    std::cout << "Vector of unique values: " << v_uniques_int;
    
    std::vector<int> v_counts_int = count_unique_values<int>( v_init_int );
    std::cout << "Vector of unique counts: " << v_counts_int;
    std::cout << "\n\n";


// Example with floats
    std::cout << "Example with floats" << std::endl;
    std::cout << "---------------------" << std::endl;
    
    std::vector<float> v_init_floats = 1.4,5.2,5.2,1.0,1.0,1.0,3.2,5.2,4.0,3.3,3.2,3.3,0.1;
    std::cout << "Initial vector: " << v_init_floats;
    
    std::vector<float> v_uniques_floats = unique_values<float>( v_init_floats );
    std::cout << "Vector of unique values: " << v_uniques_floats;
    
    std::vector<int> v_counts_floats = count_unique_values<float>( v_init_floats );
    std::cout << "Vector of unique counts: " << v_counts_floats;
    std::cout << "\n\n";


// Example with strings
    std::cout << "Example with strings" << std::endl;
    std::cout << "--------------------" << std::endl;
    
    std::vector<std::string> v_init_strings = "hi","hey","hey","hola","hola","hi","hi","hi","hola","hey","hey","hola","hi";
    std::cout << "Initial vector: " << v_init_strings;
    
    std::vector<std::string> v_uniques_strings = unique_values<std::string>( v_init_strings );
    std::cout << "Vector of unique values: " << v_uniques_strings;
    
    std::vector<int> v_counts_strings = count_unique_values<std::string>( v_init_strings );
    std::cout << "Vector of unique counts: " << v_counts_strings;

    return 0;

上述main.cpp 程序的输出将是:

Example with integers
---------------------
Initial vector: [ 1, 5, 5, 1, 1, 1, 3, 5, 4, 3, 3, 3, 0 ]
Vector of unique values: [ 0, 1, 3, 4, 5 ]
Vector of unique counts: [ 1, 4, 4, 1, 3 ]


Example with floats
---------------------
Initial vector: [ 1.4, 5.2, 5.2, 1, 1, 1, 3.2, 5.2, 4, 3.3, 3.2, 3.3, 0.1 ]
Vector of unique values: [ 0.1, 1, 1.4, 3.2, 3.3, 4, 5.2 ]
Vector of unique counts: [ 1, 3, 1, 2, 2, 1, 3 ]


Example with strings
--------------------
Initial vector: [ hi, hey, hey, hola, hola, hi, hi, hi, hola, hey, hey, hola, hi ]
Vector of unique values: [ hey, hi, hola ]
Vector of unique counts: [ 4, 5, 4 ]

【讨论】:

以上是关于计算独特项目的更好方法的主要内容,如果未能解决你的问题,请参考以下文章

小组项目简介

项目管理之项目阶段

团队开发—百科全书软件项目

快速的独特组合(来自有重复的列表),无需查找

1.4 项目描述

使用 DISTINCT 显示独特的项目