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

橙三吉。 提交于 2019-12-06 18:43:22

问题


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?


回答1:


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.

...
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()
...




回答2:


Protobuf v2

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

So 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.

Protobuf v3 update

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




回答3:


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.




回答4:


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;
        }
    }
}



回答5:


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

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);
}


来源:https://stackoverflow.com/questions/13603878/how-to-delete-arbitrary-objects-in-repeated-field-protobuf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!