C++ 如何删除重复字段中的任意对象?(protobuf)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13603878/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:32:01  来源:igfitidea点击:

How to delete arbitrary objects in repeated field? (protobuf)

c++protocol-buffers

提问by ManuelSchneid3r

I have some entries in the repeated field in my proto. Now I want delete some of them. How can I accomplish this? There is a function to delete the last element, but I want to delete arbitrary elements. I cant just swap them because the order is important.

我的原型的重复字段中有一些条目。现在我想删除其中一些。我怎样才能做到这一点?有删除最后一个元素的功能,但是我想删除任意元素。我不能只是交换它们,因为顺序很重要。

I could swap with next until end, but isn't there a nicer solution?

我可以与 next 交换直到结束,但没有更好的解决方案吗?

采纳答案by g19fanatic

According to the API docs, there isn't a way to arbitrarily remove an element from within a repeated field, just a way to remove the last one.

根据API 文档,没有办法从重复字段中任意删除元素,只能删除最后一个元素。

...
We don't provide a way to remove any element other than the last because it invites inefficient use, such as O(n^2) filtering loops that should have been O(n). If you want to remove an element other than the last, the best way to do it is to re-arrange the elements so that the one you want removed is at the end, then call RemoveLast()
...

...
我们不提供删除除最后一个元素之外的任何元素的方法,因为它会导致使用效率低下,例如 O(n^2) 过滤循环本应为 O(n)。如果要删除最后一个元素以外的元素,最好的方法是重新排列元素,使要删除的元素位于最后,然后调用 RemoveLast()
...

回答by jblixr

Protobuf v2

Protobuf v2

You can use the DeleteSubrange(int start, int num)in RepeatedPtrFieldclass.

你可以DeleteSubrange(int start, int num)RepeatedPtrField课堂上使用。

If you want to delete a single element then you have to call this method as DeleteSubrange(index_to_be_del, 1). It will remove the element at that index.

如果要删除单个元素,则必须将此方法调用为DeleteSubrange(index_to_be_del, 1). 它将删除该索引处的元素。

Protobuf v3 update

Protobuf v3 更新

As mentioned in the comments, iterator RepeatedField::erase(const_iterator position)can delete at arbitrary position

如评论中所述,iterator RepeatedField::erase(const_iterator position)可以在任意位置删除

回答by jard18

What I usually do in these cases is to create a new Protobuf (PB) message. I iterate the repeated fields of the existing message and add them (except the ones you don't want anymore) to the new PB message.

在这些情况下,我通常做的是创建一个新的 Protobuf (PB) 消息。我迭代现有消息的重复字段并将它们(除了您不再需要的那些)添加到新的 PB 消息中。

回答by user3455965

Here is example:

这是示例:

message GuiChild
{
    optional string widgetName = 1;
    //..
}

message GuiLayout
{
    repeated ChildGuiElement children = 1;
    //..
}

typedef google_public::protobuf::RepeatedPtrField<GuiChild> RepeatedField;
typedef google_public::protobuf::Message Msg;

GuiLayout guiLayout; 
//Init children as necessary..

GuiChild child;
//Set child fileds..

DeleteElementsFromRepeatedField(*child, guiLayout->mutable_children());

void DeleteElementsFromRepeatedField(const Msg& msg, RepeatedField* repeatedField)
{
    for (RepeatedField::iterator it = repeatedField->begin(); it != repeatedField->end(); it++)
    {
        if (google_public::protobuf::util::MessageDifferencer::Equals(*it, msg))
        {
            repeatedField->erase(it);
            break;
        }
    }
}

回答by Vyacheslav Napadovsky

Although there's no straight-forward method you still can do this (for custom message using reflection). Code below removes countrepeated field items starting from rowindex.

尽管没有直接的方法,您仍然可以执行此操作(对于使用反射的自定义消息)。下面的代码countrow索引开始删除重复的字段项。

void RemoveFromRepeatedField(
    const google::protobuf::Reflection *reflection,
    const google::protobuf::FieldDescriptor *field,
    google::protobuf::Message *message,
    int row,
    int count)
{
    int size = reflection->FieldSize(*message, field);
    // shift all remaining elements
    for (int i = row; i < size - count; ++i)
        reflection->SwapElements(message, field, i, i + count);
    // delete elements from reflection
    for (int i = 0; i < count; ++i)
        reflection->RemoveLast(message, field);
}