Search code examples
javascriptsalesforcevisualforceapex

Apex equivalent to Javascript For In


I have a variable that contains a list of account objects and I want to iterate through all of the fields of those accounts.

I am able to accomplish this through javascript using the below code, but I don't want to take things out of apex if I don't have to.

Does apex have an equivalent to Javascript's "IN" that would allow me to compare all fields to the same field in the next record like below?

for (var key in dataGet.accounts[i]) {
     if (dataGet.accounts[i][key] != dataGet.accounts[i+1][key]) {
     dataGet.accounts[i][key] = dataGet.accounts[i+1][key];
     }
}

Thanks!


Solution

  • To get all fields populated in one record as a key => value kind of access you can use accounts[i].getPopulatedFieldsAsMap()

    To compare all fields on 2 objects (whether they're populated or not) you should read up on "Dynamic Apex" and "describe" operations. Something like this will get you all API names on the object:

    Map<String, Schema.SObjectField> fieldsMap = Schema.SObjectType.Account.fields.getMap();
    

    And then you can iterate on the map keys

    for(String field : fieldsMap.keyset()){
        System.debug(field + ': ' + accounts[i].get(field));
    }
    

    If you don't work with sObjects but with some classes which you can't control (meaning you can't just change internal implementation to use Map<String, String> to store key-value pairs or something)... This could work. Apex doesn't have reflection.

    public with sharing class Stack47339633{
        public String name, some, other, property;
        public Integer someInt;
        public Date d;
    }
    
    Stack47339633 obj1 = new Stack47339633();
    obj1.name = 'hello';
    obj1.some = 'world';
    obj1.someInt = 13;
    obj1.d = System.today();
    
    Stack47339633 obj2 = new Stack47339633();
    obj2.name = 'hello';
    obj2.some = 'stackoverflow';
    obj2.someInt = -7;
    obj2.d = System.today();
    
    // Let's treat them as JSON objects...
    Map<String, Object> o1 = (Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(obj1));
    Map<String, Object> o2 = (Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(obj2));
    Map<String, Object> o3 = new Map<String, Object>();
    
    // ...compare, write identical fields to result object
    for(String s : o1.keyset()){
        System.debug(s + ':' + o1.get(s) + ' == ' + o2.get(s) + '?');
        if(o1.get(s) == o2.get(s)){
            System.debug('match!');
            o3.put(s, o1.get(s));
        }
    }
    
    // and cast that result object back to real class instance
    Stack47339633 obj3 = (Stack47339633) JSON.deserialize(JSON.serialize(o3), Stack47339633.class);
    System.debug('Full result: ' + obj3);
    System.debug('Name : ' + obj3.name);
    System.debug('someint : ' + obj3.someInt);
    System.debug('d : ' + obj3.d);
    

    It's not pretty with all this casting to JSON and back but it gets the job done. There will be situations where serialization can fail (for example holding references to this), if something is marked as transient it might not survive... But I don't think you'll have better option.

    Check also these: