2012-11-28 33 views
14

Tôi có một số mục nhập trong trường lặp lại trong proto của tôi. Bây giờ tôi muốn xóa một số trong số họ. Làm thế nào tôi có thể thực hiện điều này? Có một chức năng để xóa phần tử cuối cùng, nhưng tôi muốn xóa các phần tử tùy ý. Tôi không thể trao đổi chúng bởi vì thứ tự quan trọng.Làm thế nào để xóa các đối tượng tùy ý trong trường lặp lại? (protobuf)

Tôi có thể trao đổi tiếp theo cho đến khi kết thúc, nhưng không có giải pháp đẹp hơn?

+0

Có lẽ tôi quá ngu ngốc, nhưng bạn có thể giải thích sự cố của mình chi tiết hơn không? Bạn đang làm việc với khung công tác/thư viện nào? Mã nguồn? – cxxl

+0

Thư viện là bộ đệm giao thức (protobuf) từ google. Tôi đoán tôi không cần mã nguồn ở đây. Các trường lặp lại là dataholders tương tự như các container STL. – ManuelSchneid3r

+0

cho người dùng protobuf v3, hãy nhớ di chuyển ra ngoài câu trả lời được chấp nhận tại đây: https://stackoverflow.com/a/35837227/10278 – pestophagous

Trả lời

10

Theo API docs, không có cách nào để tự ý xóa phần tử khỏi trong trường lặp lại, chỉ là cách để xóa phần tử cuối cùng.

...
Chúng tôi không cung cấp một cách để loại bỏ bất kỳ yếu tố khác so với trước vì nó mời sử dụng không hiệu quả, chẳng hạn như O (n^2) lọc vòng rằng cần phải có được O (n). Nếu bạn muốn loại bỏ một phần tử khác so với lần cuối, cách tốt nhất để làm điều đó là sắp xếp lại các phần tử sao cho mà bạn muốn xóa là cuối cùng, sau đó gọi RemoveLast()
...

7

Điều tôi thường làm trong những trường hợp này là tạo thông báo Protobuf (PB) mới. Tôi lặp lại các trường lặp lại của tin nhắn hiện có và thêm chúng (ngoại trừ những trường bạn không muốn nữa) vào tin nhắn PB mới.

3

Protobuf v2

Bạn có thể sử dụng DeleteSubrange(int start, int num) trong RepeatedPtrField lớp. Nó xóa các phần tử khỏi chỉ mục start thành chỉ mục start + num - 1.

Vì vậy, nếu bạn muốn xóa một phần tử thì bạn phải gọi phương thức này là DeleteSubrange(index_to_be_del, 1). Nó sẽ xóa phần tử đơn lẻ vì index_to_be_deleted + 1 - 1 = index_to_be_del. Điều này sẽ nhân rộng đề xuất của @g19fanatic.

Protobuf v3 cập nhật

Như đã đề cập trong các ý kiến, iterator RepeatedField::erase(const_iterator position) có thể xóa ở vị trí tùy ý

+0

Tôi tò mò, tại sao không chỉ sử dụng 'erase': https: // developers .google.com/protocol-buffer/docs/reference/cpp/google.protobuf.repeated_field # RepeatedField.erase.details – johnbakers

+2

@johnbakers Vào thời điểm đó protobuf v3 không được phát hành, 'erase' không có trong protobuf v2. Nó cũng được đề cập trong câu trả lời được chấp nhận rằng họ đã không cung cấp bất kỳ phương pháp để xóa trong v2 –

+0

cảm ơn cho câu trả lời cập nhật – johnbakers

1

Dưới đây là ví dụ:

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

Mặc dù không có phương pháp thẳng về phía trước bạn vẫn có thể làm điều này (cho tin nhắn tùy chỉnh bằng cách sử dụng sự phản ánh). Mã bên dưới xóa count các mục trường lặp lại bắt đầu từ chỉ số 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); 
} 
Các vấn đề liên quan