搜索具有多个匹配的元素

时间:2010-11-12 17:35:26

标签: c++ stl

我有一个vector键值对,其中每个键值对也标有一个条目类型代码。可能的条目类型代码是:

enum Type
{
  tData = 0,
  tSeqBegin = 1,  // the beginning of a sequence
  tSeqEnd = 2     // the end of a sequence
};

所以Key-Value对本身就是这样的:

struct KeyVal
{
  int key_;
  string val_;  
  Type type_;
};

在向量内是其他键值对的子数组。这些子阵列称为“序列”。序列可以嵌套到任何级别。因此序列本身可以具有(可选的)不同长度的子序列。 Key和Type的组合在序列元素中是唯一的。也就是说,在单个序列元素中,只能有一个269数据行,但其他序列元素可以拥有自己的269数据行。

以下是一些示例数据的图形表示,过于简单(如果“类型”列为空白,则为tData类型):

Row#            Type            Key     Value      
----            -------------   -----   --------   
1                               35      "W"
2                               1181    "IBM"
3               tSeqBegin       268     "3"
4                               269     "0"
5                               270     "160.3"
6               tSeqEnd         0 
7                               269     "0"
8                               290     "0"
9               tSeqBegin       453     "1"      <-- subsequence
10              tSeqEnd         0                <-- end of subsequence
11              tSeqEnd         0
12                              269     "0"
13                              290     "1"
14                              270     "160.4"
15              tSeqEnd         0 
16                              1759    "ABC"

[编辑:关于上述内容的说明。有一个tSeqBegin标志着整个序列的开始。每个序列的末尾元素tSeqEnd标记。但是没有特殊的tSeqEnd也标志着整个序列的结束。因此,对于序列,您将看到1 tSeqBeginn tSeqEnd s,其中n是序列中元素的数量。

另一个注意事项,在从#3行开始到第15行结束的上述序列中,第二个元素中有一个子序列(第7-11行)。子序列为空,占用第9行和第10行。]

我要做的是找到一个多个键值与某些条件匹配的序列元素。例如,假设我想找到同时具有269="0" 290="0"的序列元素。在这种情况下,它不应该找到元素#0(从第3行开始),因为该元素根本没有290=...行。它应该找到从第7行开始的元素。最终我将从这个元素中提取其他字段,但这超出了这个问题的范围,所以我没有在上面包含这些数据。

我无法使用std::find_if(),因为find_if()将分别评估每一行,而不是整个序列元素作为一个单元。因此,我无法构造一个评估if 269=="0" &&* 290=="0"之类的函数的函子,因为没有一行会将此值计算为true

我原本想过实现自己的find_sequence_element(...)功能。但这将涉及一些相当复杂的逻辑。首先,我必须确定整个序列的begin()end(),并注明每个元素begin()end()的位置。然后我将构建一些我可以像这个psudocode一样串起来的评估结构:

Condition cond = KeyValueMatch(269, "0") + KeyValueMatch(290, "0");

但这也很复杂。我不能只构建一个find_sequence_element(),它只需要2个参数,一个用于269匹配,另一个用于290匹配,因为我想将此算法用于其他序列,或多或少的条件。

此外,似乎我应该能够使用已经存在的STL <algorithm>。虽然我对STL很了解,但我无法想出以任何直截了当的方式使用find_if()的方法。

所以,最后,这是问题所在。如果你遇到上述问题,你会如何解决?我知道问题很模糊。我希望通过一些讨论,我们可以缩小问题范围,直到我们得到答案。

某些条件:

  • 我无法将单个vector更改为vector of vectors或类似的任何内容。原因很复杂。

  • (更多条件的占位符:))

(如果一致认为这应该是CW,我会将其标记为)

2 个答案:

答案 0 :(得分:3)

我想以在线方式处理。有一种跟踪的类型:

  • 当前序列开始的地方
  • 计算当前序列到目前为止已满足的要求数量。

在您的示例中,要求可以表示为map<int,string>。一般来说,如果你需要在同一组中为不同条件使用不同的函子,它们可能是一系列二元谓词,或者是多态的,并且效率进展可以表示为一系列布尔值,“这个谓词已经被满足了吗? “

当您看到tSeqEnd时,您清除了满足要求的集合并重新开始。如果你的计数达到要求的数量,你就完成了。

最简单的情况是所有谓词都指定键值,因此只匹配一次。它可能看起来像:

template<typename DataIterator, typename PredIterator>
DataIterator find_matching_sequence(
  DataIterator dataFirst,
  DataIterator dataLast,
  PredIterator predFirst,
  PredIterator predLast) {
    DataIterator sequence_start = dataFirst;
    size_t required = std::distance(predFirst, predLast);
    size_t sofar = 0;
    while (dataFirst != dataLast) {
        if (dataFirst->type == SeqEnd) {
            count = 0;
            ++dataFirst;
            sequence_start = dataFirst;
            continue;
        }
        sofar += std::count(predFirst, predLast, Matches(*dataFirst));
        if (sofar == required) return sequence_start;
        ++dataFirst;
    }
}

如果同一个谓词可以匹配子序列中的多个行,那么您可以使用vector<bool>代替计数,或者可能使用valarray<bool>

为了处理多重嵌套的子序列,你实际上需要一堆“我该怎么做”的记录,你可能能够通过递归调用自身的函数实现它,并且如果它看到足够的话就提前返回“结束“记录,知道它已到达其最外层序列的末尾。但我真的不明白那部分数据格式。

所以没有认真使用STL算法,除非你想将std::copy初始范围放入执行在线处理的输出迭代器中; - )

答案 1 :(得分:2)

希望我能正确理解您的设置,我将以两步的方式进行,将搜索算法嵌套在以下几行:

template<typename It, typename Pr>
It find_sequence_element ( It begin, It end, Pr predicate );

除了Pr这里是一个带有序列的谓词,如果该序列匹配,则返回,是或否。单个匹配的示例可以是:

class HasPair
{
    int key_; string value_;
public:
    Hasmatch ( int key, string value);
    template<typename It>
    bool operator() ( It begin, It end ) const {
        return (std::find_if(begin, end, item_predicate(key_, value_));
    } 
};

item_predicate()适合在(key_,value_)中找到[begin,end)对。

如果您对查找具有两对的序列感兴趣,请编写两次调用HasPairs的{​​{1}}谓词,或者搜索两个元素的更优化版本。