Поиск и удаление уникальных значений в векторе по определенному полю кортежа

158
12 июля 2019, 07:10

С++ Есть вектор кортежей типа

std::vector <tuple< ULONG, ULONG, ULONG, time_t, wstring, int >> drv;
std::vector <drvToTuple> drv;

сначала его сортирую

bool sortbyPath(const tuple<ULONG, ULONG, ULONG, time_t, wstring, int>& a,
    const tuple<ULONG, ULONG, ULONG, time_t, wstring, int>& b)
{
    return (get<4>(a) < get<4>(b));
}
sort(drv.begin(), drv.end(), sortbyPath);

Подскажите как удалить уникальные значения основываясь на 4 поле (wstring) кортежа?

2056, 2328, 94, 1545877351, L"Sasha", 15
2057, 2328, 94, 1545877351, L"Masha", 15
2057, 2328, 94, 1545877353, L"Dasha", 15
2058, 2328, 94, 1545877353, L"Sasha", 15
2059, 2328, 94, 1545877354, L"Misha", 15
2059, 2328, 94, 1545877354, L"Misha", 15

в итоге должно остаться

2056, 2328, 94, 1545877351, L"Sasha", 15
2057, 2328, 94, 1545877351, L"Masha", 15
2057, 2328, 94, 1545877353, L"Dasha", 15
2059, 2328, 94, 1545877354, L"Misha", 15
Answer 1

Вы можете использовать комбинацию метода вектора erase со стандартным алгоритмом std::unique. (Если вы хотите поместить результат в другой вектор или контейнер, то можно использовать алгоритм std::unique_copy).

Например,

drv.erase( std::unique( std::begin( drv ), std::end( drv ), 
           []( const auto &a, const auto &b )
           {
               return std::get<4>( a ) == std::get<4>( b );
           } ), std::end( drv ) ); 

Ниже представлена демонстрационная программа

#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <vector>
#include <iterator>
#include <algorithm>
#include <ctime>
typedef unsigned long ULONG;
int main() 
{
    std::vector<std::tuple<ULONG, ULONG, ULONG, time_t, std::wstring, int>> drv =
    {
        { 056,  2328, 94, 1545877351, L"Sasha", 15 },
        { 2057, 2328, 94, 1545877351, L"Masha", 15 },
        { 2057, 2328, 94, 1545877353, L"Dasha", 15 },
        { 2058, 2328, 94, 1545877353, L"Sasha", 15 },
        { 2059, 2328, 94, 1545877354, L"Misha", 15 },
        { 2059, 2328, 94, 1545877354, L"Misha", 15 }
    };
    for ( const auto &item : drv )
    {
        std::wcout << std::setw( 4 ) << std::get<0>( item ) << ", " 
                   << std::setw( 4 ) << std::get<1>( item ) << ", "
                   << std::setw( 2 ) << std::get<2>( item ) << ", "
                   << std::get<3>( item ) << ". "
                   << std::get<4>( item ) << ", "
                   << std::get<5>( item ) << '\n';
    }       
    std::wcout << '\n';
    std::sort( std::begin( drv ), 
               std::end( drv ),
               []( const auto &a, const auto &b ) 
               { 
                    return std::get<4>( a ) < std::get<4>( b ); 
               } );
    drv.erase( std::unique( std::begin( drv ), 
               std::end( drv ),
               []( const auto &a, const auto &b )
               {
                    return std::get<4>( a ) == std::get<4>( b );
               } ), std::end( drv ) );

    for ( const auto &item : drv )
    {
        std::wcout << std::setw( 4 ) << std::get<0>( item ) << ", " 
                   << std::setw( 4 ) << std::get<1>( item ) << ", "
                   << std::setw( 2 ) << std::get<2>( item ) << ", "
                   << std::get<3>( item ) << ". "
                   << std::get<4>( item ) << ", "
                   << std::get<5>( item ) << '\n';
    }       
    return 0;
}

Ее вывод на консоль:

  46, 2328, 94, 1545877351. Sasha, 15
2057, 2328, 94, 1545877351. Masha, 15
2057, 2328, 94, 1545877353. Dasha, 15
2058, 2328, 94, 1545877353. Sasha, 15
2059, 2328, 94, 1545877354. Misha, 15
2059, 2328, 94, 1545877354. Misha, 15
2057, 2328, 94, 1545877353. Dasha, 15
2057, 2328, 94, 1545877351. Masha, 15
2059, 2328, 94, 1545877354. Misha, 15
  46, 2328, 94, 1545877351. Sasha, 15

С другой стороны, возможно вам сразу же следовало избрать другой контейнер, как, например, std::set или std::unordered_set.

Ниже представлена демонстрационная программа, которая показывает, как можно выбрать только уникальные элементы исходного вектора во множество std::set без изменения самого вектора.

#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <vector>
#include <set>
#include <iterator>
#include <algorithm>
#include <ctime>
typedef unsigned long ULONG;
int main() 
{
    std::vector<std::tuple<ULONG, ULONG, ULONG, time_t, std::wstring, int>> drv =
    {
        { 056,  2328, 94, 1545877351, L"Sasha", 15 },
        { 2057, 2328, 94, 1545877351, L"Masha", 15 },
        { 2057, 2328, 94, 1545877353, L"Dasha", 15 },
        { 2058, 2328, 94, 1545877353, L"Sasha", 15 },
        { 2059, 2328, 94, 1545877354, L"Misha", 15 },
        { 2059, 2328, 94, 1545877354, L"Misha", 15 }
    };
    for ( const auto &item : drv )
    {
        std::wcout << std::setw( 4 ) << std::get<0>( item ) << ", " 
                   << std::setw( 4 ) << std::get<1>( item ) << ", "
                   << std::setw( 2 ) << std::get<2>( item ) << ", "
                   << std::get<3>( item ) << ". "
                   << std::get<4>( item ) << ", "
                   << std::get<5>( item ) << '\n';
    }       
    std::wcout << '\n';
    auto cmp = []( const auto &a, const auto &b ) 
               { 
                    return std::get<4>( a ) < std::get<4>( b ); 
               };
    std::set<std::tuple<ULONG, ULONG, ULONG, time_t, std::wstring, int>, 
             decltype( cmp )> tuple_set( cmp );
    tuple_set.insert( std::begin( drv ), std::end( drv ) );              
    for ( const auto &item : tuple_set )
    {
        std::wcout << std::setw( 4 ) << std::get<0>( item ) << ", " 
                   << std::setw( 4 ) << std::get<1>( item ) << ", "
                   << std::setw( 2 ) << std::get<2>( item ) << ", "
                   << std::get<3>( item ) << ". "
                   << std::get<4>( item ) << ", "
                   << std::get<5>( item ) << '\n';
    }       
    std::wcout << '\n';
    return 0;
}

Вывод программы на консоль:

  46, 2328, 94, 1545877351. Sasha, 15
2057, 2328, 94, 1545877351. Masha, 15
2057, 2328, 94, 1545877353. Dasha, 15
2058, 2328, 94, 1545877353. Sasha, 15
2059, 2328, 94, 1545877354. Misha, 15
2059, 2328, 94, 1545877354. Misha, 15
2057, 2328, 94, 1545877353. Dasha, 15
2057, 2328, 94, 1545877351. Masha, 15
2059, 2328, 94, 1545877354. Misha, 15
  46, 2328, 94, 1545877351. Sasha, 15
Answer 2

Используйте std::unique() и бинарный предикат, использующий вашу функцию sortbyPath():

template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate >
ForwardIt unique( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, BinaryPredicate p );

код в итоге может быть примерно таким:

std::sort( drv.begin(), drv.end(), sortbyPath );
auto it = std::unique( drv.begin(), drv.end(), []( const auto &a, const auto &b ) {
     return not sortbyPath( a, b ) and not sortByPath( b, a ); 
} );
drv.erase( it, drv.end() );

либо можно написать еще одну функцию equalByPath(), что породит дублирование кода, но будет скорее всего более эффективным.

Если вы сортируете только для того, чтобы оставить уникальные, то это делать не обязательно, проще использовать std::unordered_set и std::remove_if:

std::unordered_set<std::wstring> uset; // тут была ошибка unoredered_set вместо unordered_set
auto it = std::remove_if( drv.begin(), drv.end(), [&uset]( const auto &d ) {
    return not uset.insert( std::get<4>( d ) ).second;
} );
drv.erase( it, drv.end() );
READ ALSO
non-constant-expression cannot be narrowed from type int to std::byte

non-constant-expression cannot be narrowed from type int to std::byte

Почему в следующем коде нет ошибок компиляции, но clang-tidy выдаёт ошибку? Компилирую с помощью gcc

177
Один QVector для разных типов объектов

Один QVector для разных типов объектов

Возник такой вопрос: у меня есть главный класс Figures, от которого я унаследовал Circle,Square,Triangle и тд

152
c++ Запись в bin файл

c++ Запись в bin файл

Начал писать свой оптимизатор-транслятор кода for funЯ новичок в c++ и ЯВУ

130
Undefined reference to &ldquo;Classname::Classname&rdquo; Qt C++

Undefined reference to “Classname::Classname” Qt C++

У меня есть проект, который содержит в себе два других (использую subdirs)Вызовом нужных функций из подпроектов занимается класс MainWindow, который...

160