std::sort 的结果不符合比较关系

result of std::sort does not fit the compare relation

提问人:jochen 提问时间:8/26/2022 最后编辑:jochen 更新时间:8/26/2022 访问量:70

问:

我在使用 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)

C++ 排序 std

评论

5赞 Ted Lyngmo 8/26/2022
What types are involved? Can you please make that into a minimal reproducible example? is almost never the correct comparison when you want a strict weak ordering btw. Please include the input container with sample data and the expected output.contains
3赞 Jarod42 8/26/2022
You want topological sorting?
7赞 Richard Critten 8/26/2022
std::sort requires a operator as the comparison operator. A classical less-than () will do this. If you implement your own comparison make sure if obeys the requirements. See C++ named requirements: Compare referenced from std::sort. Without seeing a minimal reproducible example it looks like your comparison operator does not meet the requirements.strick-weak-ordering<
1赞 463035818_is_not_an_ai 8/26/2022
I wrote a test to check the requirements of strict-weak ordering godbolt.org/z/vooKEx9cY. If I didnt miss something the comparator is fine. It just isnt the comparator you want.
1赞 463035818_is_not_an_ai 8/26/2022
you can check by writing a double loop on the resulting vector to see if for all contains(x_i, x_j) == false;i >= j

答:

1赞 jochen 8/26/2022 #1

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.