2010-06-30 6 views
8

(यह एक ठंडे फ़्यूज़न प्रश्न है)मैं दो स्ट्रक्चर पर "गहरी तुलना" या "diff" कैसे कर सकता हूं?

मेरे पास दो अलग-अलग स्ट्रक्च हैं जिनके पास एक ही डेटा हो सकता है या नहीं, और मैं यह देखने में सक्षम होना चाहता हूं कि वे क्या करते हैं! मेरे स्ट्रक्चर में हमेशा सरल मान होंगे (संख्याएं, स्ट्रिंग्स या बूलियन) क्योंकि वे DeserializeJSON के साथ बनाए जा रहे हैं, इसलिए उम्मीद है कि यह आसानी से किया जा सकता है।

मैं बेन नाडेल पद here पाया है, लेकिन है कि तकनीक मेरे लिए काम करने के लिए प्रतीत नहीं होता। (वहाँ में कुछ cfwheels कोड) यहाँ मैं अब तक क्या कोशिश की है है:

itemA = DeSerializeJSON(model("itemsnapshot").findByKey(4).json); 
itemB = DeSerializeJSON(model("itemsnapshot").findByKey(5).json); 

StructDelete(itemA,"updatedAt"); 
StructDelete(itemB,"updatedAt"); 
StructDelete(itemA,"createdAt"); 
StructDelete(itemB,"createdAt"); 

writedump(itemA); 
writedump(itemB); 

out = itemA.Equals(itemB); 
writedump(out); 

और उस के परिणाम की तरह लग रहे:

Struct 
code string C112 
companyid number 1 
cost number 5000 
deletedAt string 
description string Nightstand 
id number 70634 
itemtypeid string 13 
projectid number 8 
unittypeid string 

Struct 
code string C112 
companyid number 1 
cost number 5000 
deletedAt string 
description string Nightstand 
id number 70634 
itemtypeid string 13 
projectid number 8 
unittypeid string 

boolean false 

तो, जैसा कि आप ऊपर दिखाई देगा हालांकि, स्ट्रक्चर के अंदर डेटा ठीक से मेल खाता प्रतीत होता है कि वे बराबर() परीक्षण पास नहीं करते हैं।

किसी और को इस सफलतापूर्वक किया गया है?

+0

हम्म .. टाइपो? 'कारण "आईडी संख्या 70634" और "idnumber 70634" एक ही – Henry

+0

हाँ नहीं है जो वास्तव में एक टाइपो था! –

उत्तर

9

यहाँ बेन समाधान जल्दी से मेरी जरूरतों के लिए समायोजित है, तो आप इसे आगे भी समायोजित कर सकते हैं (और उम्मीद है कि यह pretier बनाने):

<cffunction name="DiffStructs" hint="Compute the differences between two structures" access="public" output="true" returntype="array" > 
     <cfargument name="First" type="struct" required="true" /> 
     <cfargument name="Second" type="struct" required="true" /> 
     <cfargument name="ignoreMissing" type="boolean" required="false" default="false" /> 
     <cfargument name="ignoreFirstEmptyString" type="boolean" required="false" default="false" /> 
     <cfargument name="ignoreSecondEmptyString" type="boolean" required="false" default="false" /> 

     <cfset var Result = arrayNew(1) > 
     <cfset var Keys = structNew() > 
     <cfset var KeyName = "" > 
     <cfset var obj = "" > 
     <cfset var firstOk = true > 
     <cfset var secondOk = true > 

     <cfloop collection="#Arguments.First#" item="KeyName"> 
       <cfset Keys[KeyName]=1> 
     </cfloop> 
     <cfloop collection="#Arguments.Second#" item="KeyName"> 
       <cfset Keys[KeyName]=1> 
     </cfloop> 
     <cfloop collection="#Keys#" item="KeyName"> 
      <cfif NOT StructKeyExists(Arguments.First, KeyName) > 
        <cfif NOT arguments.ignoreMissing> 
         <cfif structFind(Arguments.Second, KeyName) neq ""> 
          <cfif arguments.ignoreSecondEmptyString> 
           <cfset obj = { key = KeyName 
               ,old = "" 
               ,new = structFind(Arguments.Second, KeyName) } > 
           <cfset arrayAppend(Result, obj)> 
          </cfif> 
         </cfif> 
        </cfif> 

      <cfelseif NOT StructKeyExists(Arguments.Second, KeyName)> 
        <cfif NOT arguments.ignoreMissing> 
         <cfif structFind(Arguments.First, KeyName) neq ""> 
          <cfif arguments.ignoreFirstEmptyString > 
           <cfset obj = { key = KeyName 
               ,old = structFind(Arguments.First, KeyName) 
               ,new = "" } > 
           <cfset arrayAppend(Result, obj)> 
          </cfif> 
         </cfif> 
        </cfif> 

      <cfelseif Arguments.First[KeyName] NEQ Arguments.Second[KeyName] > 

       <cfset firstOk = true > 
       <cfset secondOk = true > 

       <cfif structFind(Arguments.Second, KeyName) eq ""> 
        <cfif arguments.ignoreSecondEmptyString> 
         <cfset firstOk = false > 
        </cfif> 
       </cfif> 

       <cfif structFind(Arguments.First, KeyName) eq ""> 
        <cfif arguments.ignoreFirstEmptyString> 
         <cfset secondOk = false > 
        </cfif> 
       </cfif> 

       <cfif firstOk AND secondOk > 
        <cfset obj = { key = KeyName 
            ,old = structFind(Arguments.First, KeyName) 
            ,new = structFind(Arguments.Second, KeyName) } > 
        <cfset arrayAppend(Result, obj)> 
       </cfif> 
      </cfif> 

     </cfloop> 

     <cfreturn Result> 
    </cffunction> 
+0

त्वरित उत्तर के लिए धन्यवाद - यह मेरी ज़रूरत के बहुत करीब है! –

+0

मुझे लगता है कि आप लाइन 37 पर 'arguments.ignoreFirstEmptyString' नहीं चाहते हैं' और लाइन 37 पर 'arguments.ignoreSecondEmptyString' नहीं। जैसा कि एक कुंजी में एक कुंजी मौजूद है लेकिन दूसरे में नहीं, यह वापस नहीं किया जाएगा। यदि आप 'NOT' का उपयोग करते हैं तो यह कुंजी को वापस कर देगा यदि यह एक संरचना में है और दूसरा नहीं। – kralco626

4

आप CF9 या Railo 3

ArrayContains([struct1], struct2); //case-sensitive 

या

उपयोग कर रहे हैं
ArrayFindNoCase([struct1], struct2)); //case-insensitive, 0 if not the same. 
ArrayContainsNoCase([struct1], struct2); // if you use Railo 
+0

महान जानकारी। हालांकि मैं अपने प्रश्न में एक साधारण सत्य या झूठी तुलना करने की कोशिश कर रहा था, ज़ारको के फ़ंक्शन द्वारा उत्पन्न diff सरणी ने मेरे इंटरफ़ेस में एक बदलाव को प्रेरित किया है जो अधिक उपयोगी कार्यक्षमता प्रदान करेगा।हालांकि, मैं पूर्ण diff चलाने से पहले प्रारंभिक जांच करने के लिए इनमें से एक का उपयोग कर सकता हूं। –

3

Coldfusion संरचनाएं में दूर छिपा हुआ एक आसान थोड़ा विधि hashCode कहा जाता है()। हालांकि ध्यान रखें कि यह अनियंत्रित है।

<cfif struct1.hashCode() Eq struct2.hashCode()> 

</cfif> 
+0

दिलचस्प! क्या आपको पता है कि यह रेलो में भी काम करता है? –

+1

नहीं, बस रेलो पर इसे आज़माएं और हैशकोड मान हमेशा अलग है। हालांकि ... st1.toString() Eq st2.toString() रेलो पर काम करता है;) –

1

आप भी इस का उपयोग करते हुए निवासी जावा विधि सीएफसी द्वारा विरासत में मिली प्रदर्शन कर सकते हैं।

isThisTrue = ObjA.equals(ObjB); 
+2

ध्यान दें कि यह वह तकनीक है जिसे मैंने प्रारंभिक पोस्ट में प्रदर्शित किया था। मेरे दो structs जो समान दिखाई देते हैं, यह "झूठी" पैदा करता है। बराबर() सभी मामलों में काम नहीं करता है। –

0

यहां कुछ ऐसा है जो मैंने जल्दी से फेंक दिया। यह निर्धारित करने के लिए पैरामीटर है कि मूल्यों और चाबियों की केस-संवेदनशील तुलना करना है या नहीं। कुछ प्रकार की यूटिलिटीज सीएफसी में इन दो कार्यों को फेंक दें (StructEquals(), ArrayEquals())।

सीमा: प्रश्न या वस्तुओं से युक्त structs/सरणियों के लिए काम नहीं करता।

<cffunction name="StructEquals" access="public" returntype="boolean" output="false" 
      hint="Returns whether two structures are equal, going deep."> 
    <cfargument name="stc1" type="struct" required="true" hint="First struct to be compared." /> 
    <cfargument name="stc2" type="struct" required="true" hint="Second struct to be compared." /> 
    <cfargument name="blnCaseSensitive" type="boolean" required="false" default="false" hint="Whether or not values are compared case-sensitive." /> 
    <cfargument name="blnCaseSensitiveKeys" type="boolean" required="false" default="false" hint="Whether or not structure keys are compared case-sensitive." /> 
    <cfscript> 
    if(StructCount(stc1) != StructCount(stc2)) 
     return false; 

    var arrKeys1 = StructKeyArray(stc1); 
    var arrKeys2 = StructKeyArray(stc2); 

    ArraySort(arrKeys1, 'text'); 
    ArraySort(arrKeys2, 'text'); 

    if(!ArrayEquals(arrKeys1, arrKeys2, blnCaseSensitiveKeys, blnCaseSensitiveKeys)) 
     return false; 

    for(var i = 1; i <= ArrayLen(arrKeys1); i++) { 
     var strKey = arrKeys1[i]; 

     if(IsStruct(stc1[strKey])) { 
     if(!IsStruct(stc2[strKey])) 
      return false; 
     if(!StructEquals(stc1[strKey], stc2[strKey], blnCaseSensitive, blnCaseSensitiveKeys)) 
      return false; 
     } 
     else if(IsArray(stc1[strKey])) { 
     if(!IsArray(stc2[strKey])) 
      return false; 
     if(!ArrayEquals(stc1[strKey], stc2[strKey], blnCaseSensitive, blnCaseSensitiveKeys)) 
      return false; 
     } 
     else if(IsSimpleValue(stc1[strKey]) && IsSimpleValue(stc2[strKey])) { 
     if(blnCaseSensitive) { 
      if(Compare(stc1[strKey], stc2[strKey]) != 0) 
      return false; 
     } 
     else { 
      if(CompareNoCase(stc1[strKey], stc2[strKey]) != 0) 
      return false; 
     } 
     } 
     else { 
     throw("Can only compare structures, arrays, and simple values. No queries or complex objects."); 
     } 
    } 

    return true; 
    </cfscript> 
</cffunction> 

<cffunction name="ArrayEquals" access="public" returntype="boolean" output="false" 
      hint="Returns whether two arrays are equal, including deep comparison if the arrays contain structures or sub-arrays."> 
    <cfargument name="arr1" type="array" required="true" hint="First struct to be compared." /> 
    <cfargument name="arr2" type="array" required="true" hint="Second struct to be compared." /> 
    <cfargument name="blnCaseSensitive" type="boolean" required="false" default="false" hint="Whether or not values are compared case-sensitive." /> 
    <cfargument name="blnCaseSensitiveKeys" type="boolean" required="false" default="false" hint="Whether or not structure keys are compared case-sensitive, if array contains structures." /> 
    <cfscript> 
    if(ArrayLen(arr1) != ArrayLen(arr2)) 
     return false; 

    for(var i = 1; i <= ArrayLen(arr1); i++) { 
     if(IsStruct(arr1[i])) { 
     if(!IsStruct(arr2[i])) 
      return false; 
     if(!StructEquals(arr1[i], arr2[i], blnCaseSensitive, blnCaseSensitiveKeys)) 
      return false; 
     } 
     else if(IsArray(arr1[i])) { 
     if(!IsArray(arr2[i])) 
      return false; 
     if(!ArrayEquals(arr1[i], arr2[i], blnCaseSensitive, blnCaseSensitiveKeys)) 
      return false; 
     } 
     else if(IsSimpleValue(arr1[i]) && IsSimpleValue(arr2[i])) { 
     if(blnCaseSensitive) { 
      if(Compare(arr1[i], arr2[i]) != 0) 
      return false; 
     } 
     else { 
      if(CompareNoCase(arr1[i], arr2[i]) != 0) 
      return false; 
     } 
     } 
     else { 
     throw("Can only compare structures, arrays, and simple values. No queries or complex objects."); 
     } 
    } 

    return true; 
    </cfscript> 
</cffunction> 

यूनिट रुचि किसी के लिए भी टेस्ट:

public void function test_StructEquals() { 
    AssertTrue(utils.StructEquals({}, StructNew())); 
    AssertTrue(utils.StructEquals({}, StructNew(), true, true)); 

    AssertFalse(utils.StructEquals({}, {"a": "b", "c": "d"})); 

    AssertTrue(utils.StructEquals({"a": "b", "c": "d"}, {"C": "D", "A": "B"})); 
    AssertFalse(utils.StructEquals({"a": "b", "c": "d"}, {"C": "D", "A": "B"}, true, false)); 
    AssertFalse(utils.StructEquals({"a": "b", "c": "d"}, {"C": "D", "A": "B"}, false, true)); 

    AssertTrue(utils.StructEquals({"a": "b", "c": "d"}, {"C": "d", "A": "b"})); 
    AssertTrue(utils.StructEquals({"a": "b", "c": "d"}, {"C": "d", "A": "b"}, true, false)); 
    AssertFalse(utils.StructEquals({"a": "b", "c": "d"}, {"C": "d", "A": "b"}, false, true)); 

    AssertTrue(utils.StructEquals({"a": "b", "c": "d"}, {"c": "D", "a": "B"})); 
    AssertFalse(utils.StructEquals({"a": "b", "c": "d"}, {"c": "D", "a": "B"}, true, false)); 
    AssertTrue(utils.StructEquals({"a": "b", "c": "d"}, {"c": "D", "a": "B"}, false, true)); 

    var stc1 = { 
    "test": { 
     "hello": "world", 
     "goodbye": "space", 
     "somearr": [ 
     { "a": 1, "b": 2 }, 
     "WORD", 
     [ 
      { "x": 97, "y": 98, "z": 99 }, 
      { "i": 50, "j": 51, "k": 52 } 
     ] 
     ] 
    } 
    }; 
    var stc2 = { 
    "test": { 
     "goodbye": "space", 
     "hello": "world", 
     "somearr": [ 
     { "a": 1, "b": 2 }, 
     "WORD", 
     [ 
      { "z": 99, "x": 97, "y": 98 }, 
      { "i": 50, "k": 52, "j": 51 } 
     ] 
     ] 
    } 
    }; 

    AssertTrue(utils.StructEquals(stc1, stc2, true, true)); 
    stc2.test.somearr[2] = "WOrD"; 
    AssertTrue(utils.StructEquals(stc1, stc2)); 
    AssertTrue(utils.StructEquals(stc1, stc2, false, true)); 
    AssertFalse(utils.StructEquals(stc1, stc2, true, false)); 
    stc2.test.somearr[3][1] = { "z": 99, "X": 97, "y": 98 }; 
    AssertTrue(utils.StructEquals(stc1, stc2)); 
    AssertFalse(utils.StructEquals(stc1, stc2, false, true)); 
    AssertFalse(utils.StructEquals(stc1, stc2, true, false)); 
    stc2.test.somearr[2] = "WORD"; 
    AssertTrue(utils.StructEquals(stc1, stc2)); 
    AssertFalse(utils.StructEquals(stc1, stc2, false, true)); 
    AssertTrue(utils.StructEquals(stc1, stc2, true, false)); 
} 

public void function test_ArrayEquals() { 
    AssertTrue(utils.ArrayEquals([], ArrayNew(1))); 
    AssertTrue(utils.ArrayEquals([], ArrayNew(1), true, true)); 

    AssertFalse(utils.ArrayEquals([], [1, 2, 3])); 

    AssertTrue(utils.ArrayEquals(['a', 'b', 'c'], ['A', 'B', 'C'])); 
    AssertFalse(utils.ArrayEquals(['a', 'b', 'c'], ['A', 'B', 'C'], true, false)); 
    AssertTrue(utils.ArrayEquals(['a', 'b', 'c'], ['A', 'B', 'C'], false, true)); 

    AssertFalse(utils.ArrayEquals(['a', 'b', 'c'], ['a', 'c', 'b'])); 

    AssertTrue(utils.ArrayEquals([1, 2, 3], [1, 2, 3])); 
    AssertFalse(utils.ArrayEquals([1, 2, 3], [1, 3, 2])); 
} 
संबंधित मुद्दे