2010-06-30 77 views
8

(这是一个coldfusion问题)如何在两个结构上进行“深层比较”或“差异”?

我有两个不同的Structs,可能包含或不包含相同的数据,我希望能够看到他们做的!我的结构将始终包含简单的值(数字,字符串或布尔值),因为它们是使用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 

所以,你会看到上面,虽然Structs内部的数据看起来完全匹配,它们没有通过Equals()测试。

任何人都有成功的做到了这一点?

+0

嗯..错字? “事业‘的ID号70634’和‘的IDNumber 70634’是不一样的 – Henry 2010-06-30 08:25:19

+0

是这确实是一个错字! – 2010-06-30 10:28:31

回答

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

感谢您的快速回复 - 这非常接近我需要! – 2010-06-30 07:40:19

+0

我想你想'不arguments.ignoreFirstEmptyString'上线25'上线37 NOT arguments.ignoreSecondEmptyString' AS是,如果一个键在一个结构存在,但不是在其他的也不会退还。如果使用“NOT”,那么如果它在一个结构中而不是另一个结构中,它将返回键。 – kralco626 2014-03-13 17:10:21

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

有关更多信息虽然我试图做我的问题简单的真或假的比较,由扎克的功能所产生的差异阵列激发了我的界面的变化而这将提供更多有用的功能。尽管如此,我可以在运行完整差异之前使用其中一个进行初始检查。 – 2010-06-30 10:26:38

3

在Coldfusion Structures中隐藏了一个名为hashCode()的方便小方法。虽然请记住,这是无证的。

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

</cfif> 
+0

有趣!你知道这是否也适用于Railo? – 2010-06-30 10:27:03

+1

不,只是在Railo上试过了,hashCode的值总是不一样。 虽然... st1.toString()等式st2.toString()适用于Railo;) – 2010-06-30 11:00:45

1

您也可以使用由CFC继承的本地Java方法执行此操作。

isThisTrue = ObjA.equals(ObjB); 
+2

请注意,这是我在初始文章中演示的技术。我的两个结构看起来很相似,它会产生“假”。 equals()在所有情况下都不起作用。 – 2011-02-02 22:59:27

0

这是我快速扔在一起的东西。它具有确定是否对值和键进行区分大小写比较的参数。在某种公用事业CFC的投掷这两个函数(StructEquals()ArrayEquals())。

限制:不适用于包含查询或对象的结构体/数组。

<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])); 
} 
相关问题