С++ Есть вектор кортежей типа
std::vector > drv;
std::vector drv;
сначала его сортирую
bool sortbyPath(const tuple& a,
const tuple& 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
Ответы
Ответ 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
#include
#include
#include
#include
#include
#include
#include
typedef unsigned long ULONG;
int main()
{
std::vector> 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
#include
#include
#include
#include
#include
#include
#include
#include
typedef unsigned long ULONG;
int main()
{
std::vector> 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,
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
Ответ 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 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() );