2008-09-02 27 views
21

Tôi muốn kết hợp hai cấu trúc với các tên trường khác nhau.Một số cách hiệu quả để kết hợp hai cấu trúc trong MATLAB là gì?

Ví dụ, bắt đầu với:

A.field1 = 1; 
A.field2 = 'a'; 

B.field3 = 2; 
B.field4 = 'b'; 

Tôi muốn có:

C.field1 = 1; 
C.field2 = 'a'; 
C.field3 = 2; 
C.field4 = 'b'; 

Có cách nào hiệu quả hơn so với sử dụng "fieldnames" và một cho vòng lặp?

EDIT: Giả sử trong trường hợp xung đột tên trường, chúng tôi ưu tiên A.

Trả lời

15

Nếu không có va chạm, bạn có thể làm

M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)']; 
C=struct(M{:}); 

Và đây là cách hợp lý hiệu quả. Tuy nhiên, struct lỗi trên tên trường trùng lặp và kiểm tra trước chúng bằng cách sử dụng unique giết hiệu suất đến mức vòng lặp tốt hơn. Nhưng đây là những gì nó sẽ như thế nào:

M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)']; 

[tmp, rows] = unique(M(1,:), 'last'); 
M=M(:, rows); 

C=struct(M{:}); 

Bạn có thể có thể làm cho một giải pháp lai bằng cách giả sử không có xung đột và sử dụng một try/catch xung quanh cuộc gọi đến struct để làm suy thoái gracefully đến cuộc xung đột xử lý vụ việc.

+0

Giải pháp đầu tiên có thể được chuyển thành một lớp lót bằng 'cell2struct'. Tôi không biết về hiệu suất của nó mặc dù. –

2

Trong C, cấu trúc có thể có cấu trúc khác là một trong các thành viên của nó. Trong khi điều này không chính xác giống như những gì bạn đang yêu cầu, bạn có thể kết thúc bằng một tình huống trong đó một cấu trúc chứa một cấu trúc khác hoặc một cấu trúc chứa hai cấu trúc, cả hai đều chứa các phần của thông tin mà bạn muốn.

psuedocode: tôi không nhớ cú pháp thực tế.

A.field1 = 1; 
A.field2 = 'a'; 
A.field3 = struct B; 

để truy cập: A.field3.field4;

hoặc thứ gì đó sắp xếp.

Hoặc bạn có thể có struct C giữ cả hai điểm A và B:

C.A = struct A; 
C.B = struct B; 

với truy cập sau đó giống như

C.A.field1; 
C.A.field2; 
C.B.field3; 
C.B.field4; 

hy vọng điều này giúp!

EDIT: cả hai giải pháp này tránh đặt tên xung đột.

Ngoài ra, tôi không thấy thẻ matlab của bạn. Theo quy ước, bạn nên chỉnh sửa câu hỏi để bao gồm phần thông tin đó.

4

Tôi không nghĩ rằng bạn có thể xử lý xung đột tốt với vòng lặp, cũng như tôi nghĩ bạn không cần phải tránh. (mặc dù tôi cho rằng hiệu quả có thể là vấn đề w/nhiều trường ...)

Tôi sử dụng hàm tôi đã viết vài năm trở lại có tên là setdefaults.m, kết hợp một cấu trúc với các giá trị của cấu trúc khác. qua trường hợp khác trong trường hợp xung đột.

% SETDEFAULTS sets the default structure values 
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S 
% all the structure fields, and their values, that exist in 
% SDEF that do not exist in S. 
% SOUT = SETDEFAULTS(S, SDEF, OVERRIDE) does 
% the same function as above, but if OVERRIDE is 1, 
% it copies all fields of SDEF to SOUT. 

function sout = setdefaults(s,sdef,override) 
if (not(exist('override','var'))) 
    override = 0; 
end 

sout = s; 
for f = fieldnames(sdef)' 
    cf = char(f); 
    if (override | not(isfield(sout,cf))) 
     sout = setfield(sout,cf,getfield(sdef,cf)); 
    end 
end 

Bây giờ tôi nghĩ về nó, tôi khá chắc chắn rằng "ghi đè" đầu vào là không cần thiết (bạn chỉ có thể chuyển đổi thứ tự của các yếu tố đầu) mặc dù tôi không phải là 100% chắc chắn về điều đó .. . vì vậy đây là một viết lại đơn giản hơn (setdefaults2.m):

% SETDEFAULTS2 sets the default structure values 
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S 
% all the structure fields, and their values, that exist in 
% SDEF that do not exist in S. 

function sout = setdefaults2(s,sdef) 
sout = sdef; 
for f = fieldnames(s)' 
    sout = setfield(sout,f{1},getfield(s,f{1})); 
end 

và một số mẫu để kiểm tra nó:

>> S1 = struct('a',1,'b',2,'c',3); 
>> S2 = struct('b',4,'c',5,'d',6); 
>> setdefaults2(S1,S2) 

ans = 

    b: 2 
    c: 3 
    d: 6 
    a: 1 

>> setdefaults2(S2,S1) 

ans = 

    a: 1 
    b: 4 
    c: 5 
    d: 6 
+0

Cảm ơn bạn, đây chính là hành vi tôi cần. Tôi tự hỏi tại sao nó không phải là một phần của thư viện chuẩn. –

+0

Theo MATLAB 6.5 (Phiên bản 13), các tham chiếu trường động có thể được sử dụng để đơn giản hóa câu lệnh bên trong vòng lặp: 'sout. (F {1}) = s. (F {1});' –

5

tôi đã tìm thấy một đẹp solution on File Exchange: catstruct.

Nếu không thử nghiệm hiệu suất, tôi có thể nói rằng nó đã làm chính xác những gì tôi muốn. Nó có thể đối phó với các lĩnh vực trùng lặp của khóa học.

Dưới đây là cách hoạt động:

a.f1 = 1; 
a.f2 = 2; 
b.f2 = 3; 
b.f4 = 4; 

s = catstruct(a,b) 

Sẽ cung cấp cho

s = 

    f1: 1 
    f2: 3 
    f3: 4 
8

Câu trả lời ngắn: setstructfields (nếu bạn có Processing Toolbox Signal).


Các giải pháp chính thức được đăng tải bởi Loren Shure trên her MathWorks blog, và chứng minh bởi SCFrench here và trong Eitan T's answer to a different question. Tuy nhiên, nếu bạn có Hộp công cụ xử lý tín hiệu, một hàm không có giấy tờ đơn giản sẽ thực hiện điều này - setstructfields.

help setstructfields

setstructfields Set fields of a structure using another structure 
    setstructfields(STRUCTIN, NEWFIELDS) Set fields of STRUCTIN using 
    another structure NEWFIELDS fields. If fields exist in STRUCTIN 
    but not in NEWFIELDS, they will not be changed. 

Bên trong nó sử dụng fieldnamesfor vòng lặp, vì vậy nó là một chức năng tiện lợi với kiểm tra lỗi và đệ quy cho các lĩnh vực mà bản thân cấu trúc.

Ví dụ

Các "gốc" struct:

% struct with fields 'color' and 'count' 
s = struct('color','orange','count',2) 

s = 
    color: 'orange' 
    count: 2 

Một struct thứ hai chứa một giá trị mới cho 'count', và một lĩnh vực mới, 'shape':

% struct with fields 'count' and 'shape' 
s2 = struct('count',4,'shape','round') 

s2 = 
    count: 4 
    shape: 'round' 

Calling setstructfields :

>> s = setstructfields(s,s2) 
s = 
    color: 'orange' 
    count: 4 
    shape: 'round' 

Trường 'count'được cập nhật. Trường 'shape'đã thêm. Trường 'color'vẫn không thay đổi.

LƯU Ý: Vì chức năng không có giấy tờ, nó có thể thay đổi hoặc bị xóa bất cứ lúc nào.