function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Sreeram VenkateshSreeram Venkatesh 

Can someone help to write the below python code in apex

rows = [
    {'Name': 'Name 1', 'Date': '06-Aug', 'Jan': 150, 'Feb': None, 'March': None, 'Apr': None, 'May': None},
    {'Name': 'Name 2', 'Date': '07-Aug', 'Jan': None, 'Feb': 100, 'March': 110, 'Apr': None, 'May': None},
    {'Name': 'Name 3', 'Date': '07-Aug', 'Jan': None, 'Feb': None, 'March': 400, 'Apr': 500, 'May': None},
]

def get_formatted_data(rows):
    data = []

    # For each row of rows
    for row in rows:

        # Loop through each key, value pair of row
        for key, val in row.items():
            data_dict = {
                'Name': row['Name'],
                'Date': row['Date']
            }
            if key not in ('Name', 'Date') and val:
                data_dict['Month'] = key
                data_dict['Rate'] = val
                data.append(data_dict)
    return data
Best Answer chosen by Sreeram Venkatesh
Gian Piere VallejosGian Piere Vallejos
Hello Sreeram,

You need to use custom classes to handle the data.
As you go in each record throught all months, I'm adding a map to handle the month's by their name and their value. 
 
public class DataDictClass {
  private List <CustomClass> init_rows_data () {
    List <CustomClass> rowsList = new List <CustomClass>();
    
    Map <String, Integer> monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 150);
    monthsMap.put('Feb', 0);
    monthsMap.put('March', 0);
    monthsMap.put('Apr', 0);
    monthsMap.put('May', 0);
    CustomClass name_1 = new CustomClass('Name 1', '06-Aug', monthsMap);
    rowsList.add(name_1);

    monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 0);
    monthsMap.put('Feb', 100);
    monthsMap.put('March', 110);
    monthsMap.put('Apr', 0);
    monthsMap.put('May', 0);
    CustomClass name_2 = new CustomClass('Name 2', '07-Aug', monthsMap);
    rowsList.add(name_2);

    monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 0);
    monthsMap.put('Feb', 0);
    monthsMap.put('March', 400);
    monthsMap.put('Apr', 500);
    monthsMap.put('May', 0);
    CustomClass name_3 = new CustomClass('Name 3', '07-Aug', monthsMap);
    rowsList.add(name_3);

    return rowsList;
  }

  private DataDict create_new_data_dict(String Name, String MyDate) {
    DataDict data_dict = new DataDict();
    data_dict.Name = Name;
    data_dict.MyDate = MyDate;
    return data_dict;
  }

  public List <DataDict> get_formatted_data() {
    List <CustomClass> rowsList = init_rows_data();
    List <DataDict> dataDictList = new List <DataDict>();
    DataDict data_dict;
    for (CustomClass cur_record : rowsList) {
      data_dict = create_new_data_dict(cur_record.Name, cur_record.MyDate);
      Set <String> monthSet = cur_record.Months.keySet();
      for (String cur_month : monthSet) {
        Integer value = cur_record.Months.get(cur_month);
        if (!cur_record.Name.contains(cur_month) && 
            !cur_record.MyDate.contains(cur_month) &&
            value <> 0 ) {
          data_dict.Month = cur_month;
          data_dict.Rate = value;
          dataDictList.add(data_dict);
        }
      }    
    }
    return dataDictList;
  }
}

public class CustomClass {
  String Name;
  String MyDate;
  Map <String, Integer> Months;
  public CustomClass(String Name, String MyDate, Map <String, Integer> Months) {
    this.Name = Name;
    this.MyDate = MyDate;
    this.Months = Months;
  }
}

public class DataDict { 
  public String Name;
  public String MyDate;
  public String Month;
  public Integer Rate;
}

DataDictClass data_dict_obj = new DataDictClass();
List <DataDict> result = data_dict_obj.get_formatted_data();
System.debug(result); //To show the result on Debug Console

If you want to convert your json data to the init class, you can go to this link: https://developer.salesforce.com/forums/?id=9060G0000005nPLQAY

Not sure what the code does, but I hope this helps.

All Answers

Gian Piere VallejosGian Piere Vallejos
Hello Sreeram,

You need to use custom classes to handle the data.
As you go in each record throught all months, I'm adding a map to handle the month's by their name and their value. 
 
public class DataDictClass {
  private List <CustomClass> init_rows_data () {
    List <CustomClass> rowsList = new List <CustomClass>();
    
    Map <String, Integer> monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 150);
    monthsMap.put('Feb', 0);
    monthsMap.put('March', 0);
    monthsMap.put('Apr', 0);
    monthsMap.put('May', 0);
    CustomClass name_1 = new CustomClass('Name 1', '06-Aug', monthsMap);
    rowsList.add(name_1);

    monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 0);
    monthsMap.put('Feb', 100);
    monthsMap.put('March', 110);
    monthsMap.put('Apr', 0);
    monthsMap.put('May', 0);
    CustomClass name_2 = new CustomClass('Name 2', '07-Aug', monthsMap);
    rowsList.add(name_2);

    monthsMap = new Map <String, Integer>();
    monthsMap.put('Jan', 0);
    monthsMap.put('Feb', 0);
    monthsMap.put('March', 400);
    monthsMap.put('Apr', 500);
    monthsMap.put('May', 0);
    CustomClass name_3 = new CustomClass('Name 3', '07-Aug', monthsMap);
    rowsList.add(name_3);

    return rowsList;
  }

  private DataDict create_new_data_dict(String Name, String MyDate) {
    DataDict data_dict = new DataDict();
    data_dict.Name = Name;
    data_dict.MyDate = MyDate;
    return data_dict;
  }

  public List <DataDict> get_formatted_data() {
    List <CustomClass> rowsList = init_rows_data();
    List <DataDict> dataDictList = new List <DataDict>();
    DataDict data_dict;
    for (CustomClass cur_record : rowsList) {
      data_dict = create_new_data_dict(cur_record.Name, cur_record.MyDate);
      Set <String> monthSet = cur_record.Months.keySet();
      for (String cur_month : monthSet) {
        Integer value = cur_record.Months.get(cur_month);
        if (!cur_record.Name.contains(cur_month) && 
            !cur_record.MyDate.contains(cur_month) &&
            value <> 0 ) {
          data_dict.Month = cur_month;
          data_dict.Rate = value;
          dataDictList.add(data_dict);
        }
      }    
    }
    return dataDictList;
  }
}

public class CustomClass {
  String Name;
  String MyDate;
  Map <String, Integer> Months;
  public CustomClass(String Name, String MyDate, Map <String, Integer> Months) {
    this.Name = Name;
    this.MyDate = MyDate;
    this.Months = Months;
  }
}

public class DataDict { 
  public String Name;
  public String MyDate;
  public String Month;
  public Integer Rate;
}

DataDictClass data_dict_obj = new DataDictClass();
List <DataDict> result = data_dict_obj.get_formatted_data();
System.debug(result); //To show the result on Debug Console

If you want to convert your json data to the init class, you can go to this link: https://developer.salesforce.com/forums/?id=9060G0000005nPLQAY

Not sure what the code does, but I hope this helps.
This was selected as the best answer
Sreeram VenkateshSreeram Venkatesh
Hi Gian Piere Vallejos,

Thanks a lot for your detailed explanation. This was very helpful and it pretty much solved my doubts. I also have an other scenario for the above mentioned code. I would be quering the above rows data from database. If that's the case, how can I proceed as the number of rows would be dynamic. Also the formatted data needs to be stored in another table. Would be helpful if you could assit on the same. Thanks in advance.

Regards,
Sreeram
Gian Piere VallejosGian Piere Vallejos

In the case you will query the rows data with SOQL you'd need to create one Object Rows (Salesforce doesn't use tables but Standard/Custom Objects) with these fields: Name, Date and Months. Months field should be a lookup field (relationship) to another Object call Months. That way you could access to the data as the next SOQL: 
 

List <Rows__c> rowsList = [SELECT Id, Name, Date, Months__r.Jan, Months__r.Feb, Months__r.March, , Months__r.Apr, , Months__r.May FROM Rows__c LIMIT 1000]; //Added the limit, because all query should be filter with WHERE clause or should be limited, that way Salesforce makes sure we are using limited resources.
 

I think you need to figure how to sort your data into custom objects of Salesforce. And also I recommend you to get more fundamentals of these platform because has a multi-tenant architecture and the way we develop should have many things to have in mind because of the shared resources between customers.

I'm leaving you some links to get more knowleadge about it: 

- https://trailhead.salesforce.com/en/content/learn/modules/starting_force_com/starting_understanding_arch
- https://trailhead.salesforce.com/content/learn/modules/apex_database?trail_id=force_com_dev_beginner

Sreeram VenkateshSreeram Venkatesh

Hi, thanks for your response. I managed to query from DB. But according to your earlier code, the final formatted data stored in result seems to be incorrect. As seen in the below log, only the last month with value is taken from each map and the records are repeated. Please find the below debug log on "result" for your reference.

result|[{"Month":"Jan","MyDate":"06-Aug","Name":"Name 1","Rate":150},{"Month":"March","MyDate":"07-Aug","Name":"Name 2","Rate":110},{"Month":"March","MyDate":"07-Aug","Name":"Name 2","Rate":110},{"Month":"Apr","MyDate":"07-Aug","Name":"Name 3","Rate":500},{"Month":"Apr","MyDate":"07-Aug","Name":"Name 3","Rate":500}]

One's highlighted in bold are repeated and also Feb from second map & march from third map are missing.