Как удалить произвольные объекты в повторяющемся поле? (Protobuf) - программирование
Подтвердить что ты не робот

Как удалить произвольные объекты в повторяющемся поле? (Protobuf)

У меня есть несколько записей в повторяющемся поле моего прото. Теперь я хочу удалить некоторые из них. Как я могу это сделать? Существует функция удаления последнего элемента, но я хочу удалить произвольные элементы. Я не могу просто заменить их, потому что порядок важен.

Я мог бы поменяться местами до конца, но нет ли лучшего решения?

4b9b3361

Ответ 1

В соответствии с API-документами нет возможности произвольно удалить элемент из повторяющегося поля, просто способ удалить последний.

...
Мы не предоставляем способ удалить любой элемент, отличный от последнего потому что он предлагает неэффективное использование, такое как петли фильтрации O (n ^ 2) это должно было быть O (n). Если вы хотите удалить элемент другой чем последний, лучший способ сделать это - это переустановить элементы так, чтобы что тот, который вы хотите удалить, находится в конце, а затем вызовите RemoveLast()
...

Ответ 2

То, что я обычно делаю в этих случаях, это создать новое сообщение Protobuf (PB). Я повторяю повторяющиеся поля существующего сообщения и добавляю их (кроме тех, которые вам больше не нужны) к новому сообщению PB.

Ответ 3

Protobuf v2

Вы можете использовать класс DeleteSubrange(int start, int num) в RepeatedPtrField. Он удаляет элементы из индекса start в индекс start + num - 1.

Итак, если вы хотите удалить один элемент, вы должны вызвать этот метод как DeleteSubrange(index_to_be_del, 1). Он удалит единственный элемент, потому что index_to_be_deleted + 1 - 1 = index_to_be_del. Это повторит предложение @g19fanatic.

Обновление Protobuf v3

Как упоминалось в комментариях, iterator RepeatedField::erase(const_iterator position) может удаляться в произвольном положении

Ответ 4

Вот пример:

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

Хотя нет прямого метода, вы все равно можете это сделать (для пользовательского сообщения с использованием отражения). Код ниже удаляет count повторяющиеся поля, начиная с 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);
}