【问题标题】:How to delete arbitrary objects in repeated field? (protobuf)如何删除重复字段中的任意对象? (protobuf)
【发布时间】:2012-11-28 11:21:46
【问题描述】:

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

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

【问题讨论】:

  • 也许我太笨了,但你能更详细地解释一下你的问题吗?您正在使用什么框架/库?源代码?
  • 该库是来自 google 的协议缓冲区 (protobuf)。我想我在这里不需要源代码。重复字段是类似于 STL 容器的数据持有者。
  • 对于 protobuf v3 的用户,请务必滚动到此处接受的答案之外:stackoverflow.com/a/35837227/10278

标签: c++ protocol-buffers


【解决方案1】:

对于 Protobuf v3

iterator RepeatedField::erase(const_iterator position)可以在任意位置删除。

对于 Protobuf v2

您可以在RepeatedPtrField 类中使用DeleteSubrange(int start, int num)

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

【讨论】:

  • 我很好奇,为什么不直接使用erase:developers.google.com/protocol-buffers/docs/reference/cpp/…
  • @johnbakers 那时 protobuf v3 还没有发布,erase 不在 protobuf v2 中。在接受的答案中还提到,他们没有提供任何在 v2 中擦除的方法
  • 我尝试 DeleteSubrange 从重复字段中删除元素但它不起作用,我尝试了 for(int var = 0; var DeleteSubrange(var,1); }
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案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】:

      虽然没有直接的方法,但您仍然可以这样做(对于使用反射的自定义消息)。下面的代码删除了从row 索引开始的count 重复字段项。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-22
        • 2021-10-12
        • 1970-01-01
        • 2015-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多