8

(这是一个冷融合问题)

我有两个不同的结构,它们可能包含也可能不包含相同的数据,我希望能够看看它们是否包含!我的结构将始终包含简单的值(数字、字符串或布尔值),因为它们是使用 DeserializeJSON 创建的,所以希望这可以轻松完成。

我在这里找到了 Ben Nadel 的帖子,但这种技术似乎对我不起作用。到目前为止,这是我尝试过的(那里有一些 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() 测试。

有没有其他人成功地做到了这一点?

4

6 回答 6

9

这是 Ben 的解决方案,可以根据我的需要快速调整,您可以进一步调整(并希望使其更漂亮):

<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>
于 2010-06-30T07:35:10.320 回答
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
于 2010-06-30T08:21:50.623 回答
3

Coldfusion Structures 中隐藏着一个方便的小方法,称为 hashCode()。尽管请记住,这是无证的。

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

</cfif>
于 2010-06-30T08:53:05.607 回答
1

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

isThisTrue = ObjA.equals(ObjB);
于 2010-12-28T23:25:20.797 回答
0
if(serializeJSON(itemA) eq serializeJSON(itemB))
  //They match!
else
  //They don't!

您已经在使用 JSON 来操作这些,您应该继续使用它。不是说十年后有人在乎,但这种方法对我有用。

于 2021-03-03T02:49:58.637 回答
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]));
}
于 2018-01-16T22:18:08.583 回答