Pregunta

(Esta es una pregunta ColdFusion)

Tengo dos Las estructuras diferentes que pueden o no pueden contener los mismos datos, y quiero ser capaz de ver si lo hacen! Las estructuras mis siempre contendrá los valores simples (números, cadenas o booleanos), ya que se están creando con DeserializeJSON, así que espero que esto se puede hacer fácilmente.

He encontrado el post de Ben Nadel aquí , pero esta técnica no parece trabajar para mí. Esto es lo que he probado hasta ahora (un código cfwheels allí):

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

Y los resultados de esa mirada como:

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

Así que, como se verá más arriba, aunque los datos dentro de los Las estructuras parecen coincidir exactamente no pasan los Iguales () de prueba.

¿Alguien más ha hecho esto con éxito?

¿Fue útil?

Solución

Aquí está la solución de Ben adaptado rápidamente a mis necesidades, puede ajustar aún más (y es de esperar que sea 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>

Otros consejos

Si está utilizando CF9 o Railo 3

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

o

ArrayFindNoCase([struct1], struct2));  //case-insensitive, 0 if not the same.
ArrayContainsNoCase([struct1], struct2); // if you use Railo

Escondido en Estructuras ColdFusion es un método poco práctico llamada hashCode (). A pesar de tener en cuenta que este es indocumentado.

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

</cfif>

También puede realizar esta usando el método nativo Java heredada por la CFC.

isThisTrue = ObjA.equals(ObjB);

Aquí hay algo que me tiró juntos rápidamente. Tiene parámetro para determinar si debe o no hacer la comparación entre mayúsculas y minúsculas de los valores y llaves. Tirar estas dos funciones (StructEquals(), ArrayEquals()) en algún tipo de utilidades de CFC.

Limitación . No funciona para structs / matrices que contienen consultas u objetos

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

Pruebas de Unidad para cualquier persona interesada:

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]));
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top