【问题标题】:filter list - C++过滤器列表 - C++
【发布时间】:2018-05-17 18:14:02
【问题描述】:

我想用 C++ 过滤一个列表。为此,我获得了一个外部函数 f,用于比较元素。基于该比较,我决定保留哪些元素。

我的实现好像有问题,你能帮我找出错误吗?

f 示例:

bool function f(a, b){
if (a + b % 3 != 0){
    return true; // keep element
}
return false; }

我想强调的是,这只是一个示例,以保持简单。

我的实现应该像这样工作(元素由___分隔):

1____2____3____4____5____6____7____8
^    ^
f(1, 2) == false. Discard 2. 

1____3____4____5____6____7____8
^    ^
now compare the next element with 1 
f(1, 3) == true. Keep 3. Move first pointer to 3

1____3____4____5____6____7____8
     ^    ^
Compare 3 with 4 ...

1____3____4____5____6____7____8
          ^    ^
remove 5, since f(4, 5) == false

1____3____4____6____7____8
          ^    ^
keep 6, move pointer 

1____3____4____6____7____8
               ^    ^
1____3____4____6____7____8
                    ^    ^
remove 8. 

1____3____4____6____7
                    ^
Nothing more to compare. Terminate. 

我通过将有效元素移动到另一个列表并将迭代器移动到原始列表中的下一个元素来实现“删除”,但实际上删除它们也可以。

list<node> result;
list<node>::iterator i = path.begin();
element firstElement = *i;
result.push_back(firstElement);
for (; i != path.end();)
{
    if (++i == path.end())
    {
        break;
    }
    // compare with next node
    int d = distance(firstElement.id, (*i).id);
    if (d <= (*i).valFrom)
    {
        // add edge to result
        result.push_back(*i);
        firstElement = *i;
    }
}

工作示例

#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
#include <list>

using namespace std;

int f(int a, int b)
{
    if (a + b % 3 == 0)
    {
        return false;
    }
    return true;
}

int main()
{

    list<int> path = {1, 2, 3, 4, 5, 6, 7, 8};
    list<int> result;
    bool skip = false;
    list<int>::iterator i = path.begin();
    int firstint = *i;
    result.push_back(firstint);
    for (; i != path.end();)
    {
        if (++i == path.end())
        {
            break;
        }
        // compare with next int
        if (f(firstint, *i))
        {
            // add edge to result
            result.push_back(*i);
            firstint = *i;
        }
    }

    // output path
    for (list<int>::iterator i = result.begin(); i != result.end(); ++i)
    {
        cout << *i << ' ';
    }
}

【问题讨论】:

  • 这是一个非常好的使用调试器的案例,一步一步执行。
  • 这也是使用单元测试的好案例。无论如何,我不确定您是否已经这样做了,但是就地过滤类似的东西通常比复制甚至移动到第二个列表更麻烦。在任何情况下,请用简单的散文为自己编写一个您想要实现的算法的逐步定义。它有助于作为稍后将其转换为 C++ 的中间步骤。
  • @UlrichEckhardt ,这就是为什么我没有这样做,而是将其编译为结果
  • f 由库提供。您可以假设它是正确的,因为它经过了彻底的测试。我不想让这篇文章过于复杂,这就是为什么我编了一个新的f
  • @n.m.我包括了一个工作示例。它做了它应该做的事,但显然并非总是如此

标签: c++ list filter iterator


【解决方案1】:

我想你想要这样的东西:

std::list<int> mylist{ 1,2,3,4,5,6,7,8,9,10 };

mylist.remove_if([](auto val)
{
    return ((val % 2) == 1);
});

这会从列表中删除所有不均匀的值

如果您希望将结果放在另一个列表中:

std::list<int> mylist{ 1,2,3,4,5,6,7,8,9,10 };
std::list<int> mylistFilered;

std::copy_if(mylist.begin(), mylist.end(), std::back_inserter(mylistFilered),[](auto val)
{
    return ((val % 2) == 1);
});

对于基于 2 个连续元素的过滤器,我们需要一个小助手列表。比如这样:

std::list<int> mylist{ 1,2,3,5,7,4,5,6,7,8,9,10 };
std::list<int> keepElement;
std::list<int> mylistFilered;

std::transform(mylist.begin(), --mylist.end(), ++mylist.begin(), std::back_inserter(keepElement),[](auto a, auto b)
{
    return ((a + b) % 3 != 0);
});

或者,如果你例如have 可以使用 -1 作为无效值,如下所示:

std::list<int> mylist{ 1,2,3,5,7,4,5,6,7,8,9,10 };
std::list<int> mylistFilered;

std::transform(mylist.begin(), --mylist.end(), ++mylist.begin(), std::back_inserter(mylistFilered),[](auto a, auto b)
{
    if ((a + b) % 3 != 0)
        return a;
    else
        return -1;
});

mylistFilered.remove_if([](auto val)
{
    return (val == -1);
});

【讨论】:

  • 我将不得不将其更改为类似的内容...我该怎么做? std::copy_if(path.begin(), path.end(), std::back_inserter(result), [](auto val) { return (distance(firstElement, SecondElement)); });
  • 因为我关心的不是特定元素的“均匀度”,而是两个元素组合的“均匀度”
  • 这不是我的问题的解决方案。如果您尝试此解决方案(输入 1、2、3、4、5、6、7、8),它将输出一个包含元素 2、3、5、6 的列表。正确的解决方案是一个包含元素 1、3、4、6
猜你喜欢
  • 2021-10-29
  • 2022-11-29
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多