我有一个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 tSeqBegin
和n
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,我会将其标记为)
答案 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}}谓词,或者搜索两个元素的更优化版本。