提问人:jochen 提问时间:8/26/2022 最后编辑:jochen 更新时间:8/26/2022 访问量:70
std::sort 的结果不符合比较关系
result of std::sort does not fit the compare relation
问:
我在使用 std::sort 时遇到了问题。
我有一堆数据并实现了一种方法,因此对数据进行排序。b ..c 使 a 包含 b,b 包含 c 等。
此方法使用其他库并产生一些约束,并且发布 ist 可能无济于事。所以我写了一个单元测试来正确测试它,但我不同意 .
我的排序调用:bool contains(const Pocket2D& other);
std::sort
std::sort(
result.begin(), result.end(), []( const auto& p1, const auto& p2 )
{
return std::get<0>( p1 ).contains( std::get<0>( p2 ) );
} );
(错误的)结果是:
03.STP 33.STP的 32.STP的 25.STP 26.STP 27.STP 28.STP 29.STP的 30.STP的 31.STP的 24.STP的 04.STP 05.stp 06.stp 07.stp 08.stp 09.stp 17.STP的 01.stp 10.stp 11.stp 12.STP的 13.STP的 14.STP的 15.STP的 16.STP的 00.stp 18.STP的 19.STP 02.STP 20.STP的 21.STP的 22.STP的 23.STP的
(10 应该在 26/27 之前而不是之后)
所以我认为 contains 方法有问题。但是后来我在 unittest 中打印了整个关系,它看起来是正确的(我省略了所有不包含任何其他轮廓的轮廓):contains
for ( auto& outerPocketTuple : result )
{
for ( const auto innerPocketTuple : result )
{
if ( std::get<0>( outerPocketTuple ).contains( std::get<0>( innerPocketTuple ) ) )
{
std::get<2>( outerPocketTuple ).push_back( std::get<1>( innerPocketTuple ) );
}
}
}
for ( const auto& r : result )
{
of << std::get<1>( r ) << ": ";
for ( const auto& ri : std::get<2>( r ) )
{
of << ri << " ";
}
of << std::endl;
}
10.stp: 26.stp 27.stp
03.stp: 00.stp 01.stp 10.stp 11.stp 12.stp 13.stp
14.stp 15.stp 16.stp 17.stp 18.stp 19.stp
02.stp 20.stp 21.stp 22.stp 23.stp 24.stp
25.stp 26.stp 27.stp 28.stp 29.stp
30.stp 31.stp 32.stp 33.stp
04.stp 05.stp 06.stp 07.stp 08.stp 09.stp
32.stp: 02.stp
33.stp: 00.stp 01.stp 10.stp 11.stp 12.stp 13.stp
14.stp 15.stp 16.stp 17.stp 18.stp 19.stp
02.stp 20.stp 21.stp 22.stp 23.stp 24.stp
25.stp 26.stp 27.stp 28.stp 29.stp
32.stp
04.stp 05.stp 06.stp 07.stp 08.stp 09.stp
我很抱歉发布数据而不是代码,但代码非常特定于用例。
我的问题是比较器看起来正确,但结果却不对。
这是我最小的例子。lambda 的作用几乎与原始罪魁祸首相同。contains
std::vector<size_t> test_data;
for ( size_t i = 0; i < 34; i++ )
{
test_data.push_back( i );
}
auto contains = []( const size_t a, const size_t b )
{
if ( a == b )
{
return false;
}
if ( a == 3 )
{
return true;
}
if ( a == 33 && b != 30 && b != 31 && b != 3 )
{
return true;
}
if ( a == 10 && ( b == 26 || b == 27 ) )
{
return true;
}
if ( a == 32 && b == 2 )
{
return true;
}
return false;
};
std::random_shuffle( test_data.begin(), test_data.end() );
std::sort( test_data.begin(), test_data.end(), contains );
for ( const auto i : test_data )
{
std::cout << i << std::endl;
}
for ( auto t = test_data.begin(); t < test_data.end(); t++ )
{
for ( auto i = t; i < test_data.end(); i++ )
{
if ( contains( *i, *t ) )
{
std::cout << "Error " << *i << " contains " << *t <<
std::endl;
}
}
}
A result may be: 3 33 32 18 8 5 21 7 12 14 20 27 6 10 1 30 9 13 4 25 23 0 2 19 22 31 26 29 17 16 24 15 11 28
Error 10 contains 27
But I need to have 3 at top, 33 above all but (30, 31), 32 above 02 and 10 above (26, 27)
答:
The relation is faulty in a strange way:
The documentation of states:Compare
If equiv(a,b)==true and equiv(b,c)==true, then equiv(a,c)==true
but
equiv(32, 29) == true
equiv(29, 02) == true
equiv(32, 02) == false
So I do need topological ordering.
评论
contains
std::sort
. Without seeing a minimal reproducible example it looks like your comparison operator does not meet the requirements.strick-weak-ordering
<
contains(x_i, x_j) == false;
i >= j