How to make elements of vector unique? (remove non adjacent duplicates)

后端 未结 11 1027
醉梦人生
醉梦人生 2020-11-29 05:01

I have a vector containing few non-adjacent duplicates.

As a simple example, consider:

2 1 6 1 4 6 2 1 1

I am trying to make this

11条回答
  •  佛祖请我去吃肉
    2020-11-29 05:37

    There is a nice article by John Torjo which deals with this very question in a systematic way. The result he comes up with seems more generic and more efficient than any of the solutions suggested here so far:

    http://www.builderau.com.au/program/java/soa/C-Removing-duplicates-from-a-range/0,339024620,320271583,00.htm

    https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-1052159.html

    Unfortunately, the complete code of John's solution seems to be no longer available, and John did not respond to may email. Therefore, I wrote my own code which is based on similar grounds like his, but intentionally differs in some details. Feel free to contact me (vschoech think-cell com) and discuss the details if you wish.

    To make the code compile for you, I added some of my own library stuff which I use regularly. Also, instead of going with plain stl, I use boost a lot to create more generic, more efficient, and more readable code.

    Have fun!

    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // library stuff
    
    template< class Rng, class Func >
    Func for_each( Rng& rng, Func f ) {
        return std::for_each( boost::begin(rng), boost::end(rng), f );
    };
    
    template< class Rng, class Pred >
    Rng& sort( Rng& rng, Pred pred ) {
        std::sort( boost::begin( rng ), boost::end( rng ), pred );
        return rng; // to allow function chaining, similar to operator+= et al.
    }
    
    template< class T >
    boost::iterator_range< boost::counting_iterator > make_counting_range( T const& tBegin, T const& tEnd ) {
        return boost::iterator_range< boost::counting_iterator >( tBegin, tEnd );
    }
    
    template< class Func >
    class compare_less_impl {
    private:
        Func m_func;
    public:
        typedef bool result_type;
        compare_less_impl( Func func ) 
        :   m_func( func )
        {}
        template< class T1, class T2 > bool operator()( T1 const& tLeft, T2 const& tRight ) const {
            return m_func( tLeft ) < m_func( tRight );
        }
    };
    
    template< class Func >
    compare_less_impl compare_less( Func func ) {
        return compare_less_impl( func );
    }
    
    
    /////////////////////////////////////////////////////////////////////////////////////////////
    // stable_unique
    
    template
    forward_iterator stable_unique(forward_iterator itBegin, forward_iterator itEnd, predicate_type predLess) {
        typedef std::iterator_traits::difference_type index_type;
        struct SIteratorIndex {
            SIteratorIndex(forward_iterator itValue, index_type idx) : m_itValue(itValue), m_idx(idx) {}
            std::iterator_traits::reference Value() const {return *m_itValue;}
            index_type m_idx;
        private:
            forward_iterator m_itValue;
        };
    
        // {1} create array of values (represented by iterators) and indices
        std::vector vecitidx;
        vecitidx.reserve( std::distance(itBegin, itEnd) );
        struct FPushBackIteratorIndex {
            FPushBackIteratorIndex(std::vector& vecitidx) : m_vecitidx(vecitidx) {}
            void operator()(forward_iterator itValue) const {
                m_vecitidx.push_back( SIteratorIndex(itValue, m_vecitidx.size()) );
            }
        private:
            std::vector& m_vecitidx;
        };
        for_each( make_counting_range(itBegin, itEnd), FPushBackIteratorIndex(vecitidx) );
    
        // {2} sort by underlying value
        struct FStableCompareByValue {
            FStableCompareByValue(predicate_type predLess) : m_predLess(predLess) {}
            bool operator()(SIteratorIndex const& itidxA, SIteratorIndex const& itidxB) {
                return m_predLess(itidxA.Value(), itidxB.Value())
                    // stable sort order, index is secondary criterion
                    || !m_predLess(itidxB.Value(), itidxA.Value()) && itidxA.m_idx < itidxB.m_idx;
            }
        private:
            predicate_type m_predLess;
        };
        sort( vecitidx, FStableCompareByValue(predLess) );
    
        // {3} apply std::unique to the sorted vector, removing duplicate values
        vecitidx.erase(
            std::unique( vecitidx.begin(), vecitidx.end(),
                !boost::bind( predLess,
                    // redundand boost::mem_fn required to compile
                    boost::bind(boost::mem_fn(&SIteratorIndex::Value), _1),
                    boost::bind(boost::mem_fn(&SIteratorIndex::Value), _2)
                )
            ),
            vecitidx.end()
        );
    
        // {4} re-sort by index to match original order
        sort( vecitidx, compare_less(boost::mem_fn(&SIteratorIndex::m_idx)) );
    
        // {5} keep only those values in the original range that were not removed by std::unique
        std::vector::iterator ititidx = vecitidx.begin();
        forward_iterator itSrc = itBegin;
        index_type idx = 0;
        for(;;) {
            if( ititidx==vecitidx.end() ) {
                // {6} return end of unique range
                return itSrc;
            }
            if( idx!=ititidx->m_idx ) {
                // original range must be modified
                break;
            }
            ++ititidx;
            ++idx;
            ++itSrc;
        }
        forward_iterator itDst = itSrc;
        do {
            ++idx;
            ++itSrc;
            // while there are still items in vecitidx, there must also be corresponding items in the original range
            if( idx==ititidx->m_idx ) {
                std::swap( *itDst, *itSrc ); // C++0x move
                ++ititidx;
                ++itDst;
            }
        } while( ititidx!=vecitidx.end() );
    
        // {6} return end of unique range
        return itDst;
    }
    
    template
    forward_iterator stable_unique(forward_iterator itBegin, forward_iterator itEnd) {
        return stable_unique( itBegin, itEnd, std::less< std::iterator_traits::value_type >() );
    }
    
    void stable_unique_test() {
        std::vector vecn;
        vecn.push_back(1);
        vecn.push_back(17);
        vecn.push_back(-100);
        vecn.push_back(17);
        vecn.push_back(1);
        vecn.push_back(17);
        vecn.push_back(53);
        vecn.erase( stable_unique(vecn.begin(), vecn.end()), vecn.end() );
        // result: 1, 17, -100, 53
    }
    

提交回复
热议问题