web-dev-qa-db-ja.com

繰り返しフィールド内の任意のオブジェクトを削除するにはどうすればよいですか? (protobuf)

プロトの繰り返しフィールドにいくつかのエントリがあります。今、私はそれらのいくつかを削除したいと思います。どうすればこれを達成できますか?最後の要素を削除する機能がありますが、任意の要素を削除したいのですが。順番が重要なので、交換することはできません。

私は最後まで次と交換することができましたが、より良い解決策はありませんか?

18
ManuelSchneid3r

API docs によると、繰り返されるフィールド内から要素を任意に削除する方法はなく、最後の要素を削除する方法だけです。

.。
O(n)であるはずのO(n ^ 2)フィルタリングループなど、非効率的な使用を招くため、最後の要素以外の要素を削除する方法は提供していません。最後以外の要素を削除する場合は、削除する要素が最後になるように要素を再配置してから、RemoveLast()を呼び出すのが最善の方法です。
.。

11
g19fanatic

Protobuf v2

RepeatedPtrFieldクラスでDeleteSubrange(int start, int num)を使用できます。

したがって、単一の要素を削除する場合は、このメソッドをDeleteSubrange(index_to_be_del, 1)として呼び出す必要があります。そのインデックスの要素を削除します。

Protobuf v3アップデート

コメントで述べたように、 iterator RepeatedField::erase(const_iterator position) は任意の位置で削除できます

11
jblixr

これらの場合に私が通常行うことは、新しいProtobuf(PB)メッセージを作成することです。既存のメッセージの繰り返されるフィールドを繰り返し、それらを新しいPBメッセージに追加します(不要になったフィールドを除く)。

8
jard18

次に例を示します。

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

簡単な方法はありませんが、これを行うことができます(リフレクションを使用したカスタムメッセージの場合)。以下のコードは、countインデックスから始まるrow繰り返しフィールドアイテムを削除します。

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