ما هي بعض الطرق الفعالة للجمع بين بنيتين في MATLAB؟

StackOverflow https://stackoverflow.com/questions/38645

  •  09-06-2019
  •  | 
  •  

سؤال

أريد الجمع بين بنيتين بأسماء حقول مختلفة.

على سبيل المثال، البدء بـ:

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

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

أود أن أحصل على:

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

هل هناك طريقة أكثر فعالية من استخدام "أسماء الحقول" وحلقة for؟

يحرر: لنفترض أنه في حالة تعارض أسماء الحقول فإننا نعطي الأفضلية A.

هل كانت مفيدة؟

المحلول

بدون اصطدامات، يمكنك القيام بذلك

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

وهذا فعال بشكل معقول.لكن، struct الأخطاء في أسماء الحقول المكررة، والتحقق المسبق منها باستخدام unique يقتل الأداء لدرجة أن الحلقة أفضل.ولكن هنا ما سيبدو عليه:

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

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

C=struct(M{:});

قد تكون قادرًا على تقديم حل مختلط من خلال افتراض عدم وجود تعارضات واستخدام محاولة/التقاط حول المكالمة struct للتحلل بأمان في حالة التعامل مع الصراع.

نصائح أخرى

اجابة قصيرة: setstructfields (إذا كان لديك صندوق أدوات معالجة الإشارة).


يتم نشر الحل الرسمي بواسطة لورين شور على مدونتها MathWorks, ، وأظهر SCالفرنسية هنا و في إجابة إيتان تي على سؤال مختلف.ومع ذلك، إذا كان لديك صندوق أدوات معالجة الإشارات، فهناك وظيفة بسيطة غير موثقة تقوم بذلك بالفعل - 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.

داخليا يستخدم fieldnames و أ for Loop، لذا فهي وظيفة ملائمة مع التحقق من الأخطاء والتكرار للحقول التي هي في حد ذاتها بنيات.

مثال

الهيكل "الأصلي":

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

s = 
    color: 'orange'
    count: 2

بنية ثانية تحتوي على قيمة جديدة لـ 'count', ، ومجال جديد، 'shape':

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

s2 = 
    count: 4
    shape: 'round'

الاتصال setstructfields:

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

الميدان 'count' يكون محدث.الميدان 'shape' يكون وأضاف.الميدان 'color' يبقى دون تغيير.

ملحوظة:نظرًا لأن الوظيفة غير موثقة، فقد تتغير أو تتم إزالتها في أي وقت.

لقد وجدت لطيفة الحل في تبادل الملفات:com.catstruct.

بدون اختبار الأداء أستطيع أن أقول أنه فعل بالضبط ما أردت.يمكنه التعامل مع الحقول المكررة بالطبع.

وهنا كيف يعمل:

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

s = catstruct(a,b)

سنعطي

s = 

    f1: 1
    f2: 3
    f3: 4

لا أعتقد أنك تستطيع التعامل مع الصراعات بشكل جيد بدون حلقة، ولا أعتقد أنك ستحتاج إلى تجنبها.(على الرغم من أنني أفترض أن الكفاءة يمكن أن تكون مشكلة في العديد من المجالات...)

أستخدم وظيفة كتبتها قبل بضع سنوات تسمى setdefaults.m, والتي تجمع بين بنية واحدة وقيم بنية أخرى، حيث يكون لأحدهما الأسبقية على الآخر في حالة التعارض.

% 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

الآن بعد أن أفكر في الأمر، أنا متأكد تمامًا من أن إدخال "التجاوز" غير ضروري (يمكنك فقط تبديل ترتيب المدخلات) على الرغم من أنني لست متأكدًا من ذلك بنسبة 100%...إذن إليك إعادة كتابة أبسط (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

وبعض العينات لاختباره:

>> 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

في لغة C، يمكن أن تحتوي البنية على بنية أخرى كأحد أعضائها.على الرغم من أن هذا ليس هو نفسه تمامًا ما تطلبه، فقد ينتهي بك الأمر إما إلى موقف تحتوي فيه إحدى البنية على أخرى، أو تحتوي إحدى البنية على بنيتين، وكلاهما يحتوي على أجزاء من المعلومات التي تريدها.

الكود الكاذب:لا أتذكر بناء الجملة الفعلي.

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

للوصول:A.field3.field4;

أو شيء من هذا القبيل.

أو يمكن أن يكون لديك البنية C التي تحمل كلا من A وB:

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

مع الوصول ثم شيء من هذا القبيل

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

أتمنى أن يساعدك هذا!

يحرر:كلا الحلين يتجنبان تسمية التصادمات.

وأيضاً لم أشاهد تواجدك matlab بطاقة شعار.وفقًا للاتفاقية، يجب أن ترغب في تعديل السؤال ليشمل هذه المعلومة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top