stl向量中的唯一值

时间:2018-05-18 09:41:55

标签: c++ vector

我有以下代码,用于计算向量

中的唯一值
bool uniqueCompressVectorCompareFunction (unsigned int num1, unsigned int num2) {
  return (num1 == num2);
}


// redirect input from stream to file.
std::ifstream inputFile("testinput.txt");
std::streambuf* pcurrRdBuf = std::cin.rdbuf();
std::cin.set_rdbuf(inputFile.rdbuf());

unsigned int uiNoOfFishes = 0;
std::cin >> uiNoOfFishes;
std::vector<unsigned int> vecOfLenOfFishes(uiNoOfFishes);
std::vector<unsigned int> vecOfTimeHeadOfFishes(uiNoOfFishes);

// get length of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfLenOfFishes[uiIdx];
}

// get time head of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfTimeHeadOfFishes[uiIdx];
}

std::cout << "Actual input length of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfLenOfFishes.size(); uiIdx++) {
    std::cout << vecOfLenOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;

std::cout << "Actual input time head of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfTimeHeadOfFishes.size(); uiIdx++) {
    std::cout << vecOfTimeHeadOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;


std::vector<unsigned int> vecUniqueInputValues;
// copy length of fishes.
unsigned int uiUniqueVecIdx = 0;
for(; uiUniqueVecIdx < uiNoOfFishes; uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back(vecOfLenOfFishes[uiUniqueVecIdx]);
}

// copy time head of fishes.
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++, uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back( vecOfTimeHeadOfFishes[uiIdx]);
}

// using predicate comparison:
std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), uniqueCompressVectorCompareFunction); 



std::cout << "compressInputData unique values sorted: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecUniqueInputValues.size(); uiIdx++) {
    std::cout << vecUniqueInputValues[uiIdx] << "   ";
}
std::cout << std::endl;

// testinput.txt中的内容在

之下
5
2 4 4 2 4
1 4 1 6 4

输出显示如下

Actual input length of fishes:
2   4   4   2   4
Actual input time head of fishes:
1   4   1   6   4
compressInputData total values:
2   4   4   2   4   1   4   1   6   4
compressInputData unique values sorted:
2   4   2   4   1   4   1   6   4   4

我期待压缩输入的唯一值应该是 1 2 4 6

我的代码中有什么错误?

3 个答案:

答案 0 :(得分:2)

根据documentation of std::unique

  

[e]限制除了连续等效元素组中的第一个元素之外的所有元素

(强调我的)。

因此,它不会删除所有重复的值,只删除相邻的值,例如[1 2 2 3 3 3 1 1 3 3 2 2]减少到[1 2 3 1 3 2]

如果您只想保留整体唯一元素,则应首先对矢量进行排序:

std::sort(vecUniqueInputValues.begin(), vecUniqueInputValues.end());

// Vector is now [1, 1, 2, 2, .., 2, 4, .., 4, 5, ... ]

std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), 
  uniqueCompressVectorCompareFunction); 

一些小问题

比较函数似乎有点多余 - 如果你没有指定它

  

[e] lements使用operator==进行比较。

另请注意,std::unique实际上只是对元素进行混洗,以便所有唯一的连续元素都位于向量的开头 - 您仍然会在输出结束时看到值4两次。你应该抓住std::unique的结果 - 它是一个迭代器,指向一个超出唯一范围末尾的迭代器:

auto endOfUniqueRange = std::unique(...);

std::cout << "compressInputData unique values sorted: " << std::endl;
for(auto& uiIt = vecUniqueInputValues.cbegin(); uiIt != endOfUniqueRange ; ++uiIt) {
    std::cout << *uiIt << "   ";
}
std::cout << std::endl;

实际上我建议您使用迭代器和基于范围的for循环:而不是

for(auto i = 0; i < myVec.size(); ++i) {
  // Do something with myVec[i]
}

for(auto it = myVec.cbegin(); it != myVec.cend(); ++it) {
  // Do something with *it
}

或者,迭代整个向量,

for(unsigned int val : myVec) { 
  // Do something with val
}

答案 1 :(得分:2)

来自the docs

  

std::unique[first, last)范围内的每个连续等效元素组中消除除第一个元素之外的所有元素,并为该范围的新逻辑结束返回一个过去的结束迭代器。

看到连续这个词,这意味着如果向量被排序,它只会删除重复项,并且重复是连续的顺序。

在调用std::unique

之前对矢量进行排序

答案 2 :(得分:0)

正如其他答案所指出的,std::unique删除了连续的重复项。这允许它是单程算法。

如果要在不更改剩余元素顺序的情况下删除非连续重复项,则必须编写不同的函数来执行此操作。这通常需要在输入范围内多次通过。

这是一个简单的实现,以匹配std::unique

的签名
template <typename ForwardIterator>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that are equal to the current
        // Any values removed shorten the range to search
        last = std::remove(std::next(first), last, *first);
    }
    return last;
}

接受BinaryPredicate

的变体
template <typename ForwardIterator, typename BinaryPredicate>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that satisfy the predicate
        // Any values removed shorten the range to search
        last = std::remove_if(std::next(first), last, [=](auto val){ return pred(*first, val); });
    }
    return last;
}