Mac solved command not found: compdef
Posted on July 16, 2020 Leave a Comment
Follow these steps to install nvm using homebrew
https://www.wdiaz.org/how-to-install-nvm-with-homebrew/
Confirm echo $HOME/.nvm returns
/Users/{your username}/.nvm
Now let’s edit zshrc to add nvm bash_completion
vi ~/.zshrc
Add the following lines to the top of the file
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion autoload -Uz compinit compinit
Note: Make sure you add this snippet before any call to compdef else you will still see the error
Reload the terminal and the errors should be gone
Apex Coding Interview Challenge #11
Posted on July 7, 2020 Leave a Comment
Given an integer k and a string s, find the length of the longest substring that contains at most k distinct characters.
For example, given s = “abcba” and k = 2, the longest substring with k distinct characters is “bcb”.
Solution
public static String getLongestSubstringDistinct(String str, Integer k){ Integer n = str.length(); Integer left = 0; Integer right = 0; Map<Integer, Integer> mapOfChars = new Map<Integer, Integer>(); while (right < n){ if (mapOfChars.size() < k+1){ if (!mapOfChars.containsKey(str.charAt(right))){ mapOfChars.put(str.charAt(right), right); } else if (right-mapOfChars.get(str.charAt(right))<=1){ mapOfChars.put(str.charAt(right), right); } right++; } System.debug('mapOfChars > ' + mapOfChars); if (mapOfChars.size() == k+1){ List<Integer> mapOfValues = mapOfChars.values(); mapOfValues.sort(); Integer leftMax = mapOfValues.get(0); mapOfChars.remove(str.charAt(leftMax)); left = leftMax + 1; } } List<Integer> charStartEnd = mapOfChars.values(); charStartEnd.sort(); return str.subString(charStartEnd.get(0)-1, charStartEnd.get(1)); }
Testing
System.debug(getLongestSubstringDistinct('abcba', 2)); //bcb System.debug(getLongestSubstringDistinct('zxybobc', 2)); //bob
Apex Coding Interview Challenge #10
Posted on July 6, 2020 Leave a Comment
Given a string of round, curly, and square open and closing brackets, return whether the brackets are balanced (well-formed).
For example, given the string “([])[]({})”, you should return true.
Given the string “([)]” or “((()”, you should return false.
There is are Stack implementation currently available in Apex so we can use a List to push and pop characters
Solution
public class Stack { private List<Object> items {get; set;} public Stack() { this.items = new List<Object>(); } public Integer size() { return this.items.size(); } public Boolean isEmpty() { return size() == 0; } public void push(Object itemToPush) { this.items.add(itemToPush); } public Object pop() { if (isEmpty()) { throw new EmptyStackException(); } return this.items.remove(size() - 1); } public Object peek() { if (isEmpty()) { throw new EmptyStackException('Stack is empty'); } return this.items.get(size() - 1); } } public class EmptyStackException extends Exception {} public static Map<String, String> mapBrackets(){ Map<String, String> bracketMap = new Map<String, String>(); bracketMap.put('}', '{'); bracketMap.put(')', '('); bracketMap.put(']', '['); return bracketMap; } public static Boolean checkClosingBrackets(String bracketStr) { Map<String, String> bracketMap = mapBrackets(); Stack customStack = new Stack(); for (Integer i=0; i < bracketStr.length(); i++){ String str = bracketStr.substring(i,i+1); System.debug('> ' + str); if (!bracketMap.containsKey(str)){ customStack.push((String)str); } else { String pop = (String)customStack.pop(); String mappedVal = bracketMap.get(str); if (!mappedVal.equals(pop)){ return false; } } } if (!customStack.isEmpty()){ return false; } return true; }
Testing
System.debug(checkClosingBrackets('([])[]({})')); //true System.debug(checkClosingBrackets('([])[]({}')); //false
Apex Coding Interview Challenge #9
Posted on July 6, 2020 Leave a Comment
Given a list of integers, write a function that returns the largest sum of non-adjacent numbers. Numbers can be 0 or negative.
For example, [2, 4, 6, 2, 5] should return 13, since we pick 2, 6, and 5. [5, 1, 1, 5] should return 10, since we pick 5 and 5.
Follow-up: Can you do this in O(N) time and constant space?
Solution
public Integer sumLargestNonAdjacentNumbers(List<Integer> lstNumbers){ Integer exclusive = 0; Integer inclusive = lstNumbers.get(0); for (Integer i = 1; i < lstNumbers.size(); i++) { Integer temp = inclusive; inclusive = Math.max(exclusive + lstNumbers.get(i), inclusive); exclusive = temp; } return inclusive; }
Testing
System.debug(sumLargestNonAdjacentNumbers(new List<Integer>{5, 1, 1, 5})); //10 System.debug(sumLargestNonAdjacentNumbers(new List<Integer>{2, 4, 6, 2, 5})); //13
Complexity Analysis
Time complexity: O(n)
Space complexity: O(1)
Apex Coding Interview Challenge #8
Posted on June 29, 2020 2 Comments
Implement an autocomplete system. That is, given a query string s and a set of all possible query strings, return all strings in the set that have s as a prefix.
For example, given the query string de and the set of strings [dog, deer, deal], return [deer, deal].
Hint: Try preprocessing the dictionary into a more efficient data structure to speed up queries.
Solution
public Map<String, List<String>> mapOfDictionary(List<String> wordsLst){ Map<String, List<String>> dictionaryMap = new Map<String, List<String>>(); for (String w : wordsLst){ List<String> wordChars = new List<String>(w.split('')); String concatChars = ''; for (String wordChar : wordChars){ concatChars += wordChar; if (dictionaryMap.containsKey(concatChars)){ List<String> wordsForChars = dictionaryMap.get(concatChars); wordsForChars.add(w); dictionaryMap.put(concatChars, wordsForChars); } else { dictionaryMap.put(concatChars, new List<String>{w}); } } } return dictionaryMap; } public List<String> getWordsForAutoComplete(String word){ Map<String, List<String>> dictionaryMap = mapOfDictionary(new List<String>{'dog', 'deer', 'deal'}); return dictionaryMap.get(word); }
Testing
System.debug(getWordsForAutoComplete('de')); //(deer, deal)
Complexity Analysis
Time complexity: O(n^2)
Space complexity: O(m*n) //m – max length of string, n – amount of words
Apex Coding Interview Challenge #7
Posted on June 25, 2020 Leave a Comment
Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.
For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should give 3.
Solution
public Integer lowestIntMissingFromLst(List<Integer> intVals){ Integer missingNum = 0; Integer maxVal = 0; Integer maxMin = 0; Integer maxMax = 0; for (Integer k = 0; k < intVals.size(); k++){ if (k == 0){ maxVal = intVals.get(k); } else if (maxVal < intVals.get(k)){ maxVal = intVals.get(k); maxMin = intVals.get(k) - intVals.size(); maxMax = intVals.get(k) + intVals.size(); } Integer plusOne = intVals.get(k)+1; Integer minusOne = intVals.get(k)-1; if (plusOne < maxMax && !intVals.contains(plusOne)){ missingNum = plusOne; } else if (minusOne < maxMin && !intVals.contains(minusOne)){ missingNum = minusOne; } } return missingNum; }
Test
System.debug(lowestIntMissingFromLst(new List<Integer>{3, 4, -1, 1})); //2 System.debug(lowestIntMissingFromLst(new List<Integer>{1, 2, 0})); //3
Complexity Analysis
Time complexity: O(n)
Space complexity: O(1)
Apex Coding Interview Challenge #6
Posted on June 24, 2020 Leave a Comment
Given an array of integers, return a new array such that each element at index i of the new array is the product of all the numbers in the original array except the one at i.
For example, if our input was [1, 2, 3, 4, 5], the expected output would be [120, 60, 40, 30, 24]. If our input was [3, 2, 1], the expected output would be [2, 3, 6].
Solution
public List<Integer> productOfNumbers(List<Integer> intVals){ List<Integer> productLst = new List<Integer>(); for (Integer k = 0; k < intVals.size(); k++){ Integer sumOfVals = 1; // it's 1 because multiplying by 0 will always be 0 for (Integer j = 0; j < intVals.size(); j++){ if (j != k){ sumOfVals *= intVals.get(j); } } productLst.add(sumOfVals); } return productLst; }
Test
System.debug(productOfNumbers(new List<Integer>{1, 2, 3, 4, 5})); //(120, 60, 40, 30, 24) System.debug(productOfNumbers(new List<Integer>{3, 2, 1})); //(2, 3, 6)
Complexity Analysis
Time complexity: O(n2)
Space complexity: O(n)
Apex Coding Interview Challenge #2
Posted on June 19, 2020 Leave a Comment
Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17.
Bonus: Can you do this in one pass?
Solution
public Boolean checkNumberAddToK(List<Integer> intVals, Integer k){ Boolean sumAddsUpFlag = false; Set<Integer> diffVals = new Set<Integer>(); for (Integer intVal : intVals){ if (diffVals.isEmpty()){ diffVals.add(k-intVal); } else { if (diffVals.contains(intVal)){ sumAddsUpFlag = true; break; } else { diffVals.add(k-intVal); } } } return sumAddsUpFlag; }
Test
System.debug(checkNumberAddToK(new List{10, 15, 3, 7}, 17)); //return true System.debug(checkNumberAddToK(new List{10, 15, 3, 8}, 17)); //return false
Complexity Analysis
Time complexity: O(n)
Space complexity: O(n)
Apex Coding Interview Challenge #1
Posted on June 18, 2020 Leave a Comment
This question was asked during an Amazon interview
Following schema is provided:
Account
Total_Salary__c (Number)
Max_Salary__c (Number)
Account_Salary__c
Account__c (lookup)
Name (String)
Salary__c (Number)
An Account can have multiple Account_Salary__c records that lookup to an Account by the Account__c.
Write a trigger that would update the Account Total_Salary__c, Max_Salary__c when a new Account salary record is:
- Inserted
- Update
- Deleted
- Undeleted
Declarative Programming solution
- Master Detail relationship between Account and Account_Salary__c, use sum(Salary__c) and max(Salary__c) to do rollup to Account
- Process Builder or Flow that calls out to @InvocableMethod to query all other Account_Salary__c records and makes the update
Imperative Programming solution
Trigger
trigger AccountSalaryTrigger on Account_Salary__c (after insert, after update, after delete, after undelete) { if (Trigger.isUpdate){ AccountSalaryHelper.updateAccount(Trigger.new, Trigger.oldMap); } else if (Trigger.isDelete){ AccountSalaryHelper.updateAccount(Trigger.old, null); } else { AccountSalaryHelper.updateAccount(Trigger.new, null); } }
Helper class
public with sharing class AccountSalaryHelper { public static void updateAccount(List<Account_Salary__c> newAccountSalaries, Map<Id, Account_Salary__c> oldMap){ Set<Id> accountIds = new Set<Id>(); for (Account_Salary__c newAccountSalary : newAccountSalaries){ if (oldMap!=null){ Account_Salary__c oldAccountSalary = oldMap.get(newAccountSalary.Id); if (oldAccountSalary.Salary__c != newAccountSalary.Salary__c){ accountIds.add(newAccountSalary.Account__c); } } else { accountIds.add(newAccountSalary.Account__c); } } if (!accountIds.isEmpty()){ List<AggregateResult> aggResults = [Select Account__c accId, sum(Salary__c) sumSalary, max(Salary__c) maxSalary from Account_Salary__c where Account__c IN :accountIds Group By Account__c]; List<Account> accountsToUpdate = new List<Account>(); for (AggregateResult aggResult : aggResults){ Id accountId = (Id)aggResult.get('accId'); if (accountId!=null){ Account updateAccount = new Account(); updateAccount.Id =accountId; updateAccount.Total_Salary__c=(Decimal)aggResult.get('sumSalary'); updateAccount.Max_Salary__c = (Decimal)aggResult.get('maxSalary'); accountsToUpdate.add(updateAccount); } } if (!accountsToUpdate.isEmpty()){ SavePoint sp = Database.setSavePoint(); try{ update accountsToUpdate; } catch(DMLException ex){ Database.rollback(sp); } } } } }
Helper Test class
@isTest private class AccountSalaryHelperTest { @TestSetup static void setup(){ Account acc = new Account(); acc.Name = 'Test'; insert acc; Account_Salary__c as1 = new Account_Salary__c(); as1.Name='as1'; as1.Account__c = acc.Id; as1.Salary__c = 500; insert as1; Account_Salary__c as2 = new Account_Salary__c(); as2.Name = 'as2'; as2.Account__c = acc.Id; as2.Salary__c = 700; insert as2; } @isTest static void testInsertAccountSalary(){ Account acc = [Select Id, Max_Salary__c, Total_Salary__c from Account][0]; Test.startTest(); Account_Salary__c as3 = new Account_Salary__c(); as3.Name = 'as3'; as3.Account__c = acc.Id; as3.Salary__c = 300; insert as3; Test.stopTest(); Account accAfter = [Select Id, Max_Salary__c, Total_Salary__c from Account][0]; System.assertEquals(accAfter.Max_Salary__c, 700); System.assertEquals(accAfter.Total_Salary__c, 1500); } @isTest static void testUpdateAccountSalary(){ Account_Salary__c accSalary = [Select Id, Salary__c from Account_Salary__c where Name='as2'][0]; Test.startTest(); accSalary.Salary__c = 800; update accSalary; Test.stopTest(); Account acc = [Select Id, Max_Salary__c, Total_Salary__c from Account][0]; System.assertEquals(acc.Max_Salary__c, 800); System.assertEquals(acc.Total_Salary__c, 1300); } @isTest static void testDeleteAccountSalary(){ Test.startTest(); delete [Select Id from Account_Salary__c where Name='as2'][0]; Test.stopTest(); Account acc = [Select Id, Max_Salary__c, Total_Salary__c from Account][0]; System.assertEquals(acc.Max_Salary__c, 500); System.assertEquals(acc.Total_Salary__c, 500); } }
Follow up question
1. How can we make the trigger more dynamic so when a new field is added it would do the max and sum on account
Answer:
Create a custom metadata mapper table that would contain the SOQL query values and then related Account mapped fields. Create a dynamic SOQL query reading the fields that needs to be queried from custom metadata. Use the SObject set method to set the field values. Account.put(‘Total_Salary_Count__c’, (Decimal)aggResult.get(‘countSalary’));
Apex Pass by Reference Pass by Value Examples
Posted on June 3, 2020 Leave a Comment
Pass by value – all primitive data type arguments, such as Integer or String, are passed into methods by value. This means that any changes to the arguments exist only within the scope of the method. When the method returns, the changes to the arguments are lost.
Non-primitive data type arguments, such as sObjects, are also passed into methods by value. This means that when the method returns, the passed-in argument still references the same object as before the method call, and can’t be changed to point to another object. However, the values of the object’s fields can be changed in the method.
Pass by reference means when a method is called, that actual variable is passed to the method
Pass by reference
A map with String key and List as value
Map<String, List<String>> mapOfLst = new Map<String, List<String>>(); mapOfLst.put('test', new List<String>{'1'}); System.debug('test 1 > ' + mapOfLst.get('test')); // (1) List<String> lstOfMap = mapOfLst.get('test'); lstOfMap.add('2'); System.debug('test 2 > ' + mapOfLst.get('test')); // (1, 2)
Note we do not have to put the list back to the map, like this:
mapOfLst.put(‘test’, lstOfMap);
This is unnecessary as the List is passed by reference and we can just add the value to the list and will be available in the map when we do a get by key
public class StrUtil { private String str; public StrUtil(String str){ this.str = str; } public void setStr(String str){ this.str = str; } } Map<String, StrUtil> mapOfLst = new Map<String, StrUtil>(); mapOfLst.put('test', new StrUtil('1')); System.debug('test 1 > ' + mapOfLst.get('test')); //StrUtil:[str=1] StrUtil str = mapOfLst.get('test'); str.setStr('2'); System.debug('test 2 > ' + mapOfLst.get('test')); //StrUtil:[str=2]
Works same when we use objects no need to put the update object back to map as it is passed by reference
Pass by value
Map<String, String> mapOfLst = new Map<String, String>(); mapOfLst.put('test', '1'); System.debug('test 1 > ' + mapOfLst.get('test')); //1 String str = mapOfLst.get('test'); str = '2'; System.debug('test 2 > ' + mapOfLst.get('test')); //1
Pass by value will not update the value of the map and we need to put value back to map
mapOfLst.put(‘test’, str);
Account acc = [Select Id, Name from Account limit 1][0]; public static Account setAccountName(Account acc){ acc.Name = 'Update Name'; return acc; } System.debug('>> ' + setAccountName(acc)); //still same account but Name field was changed
SObject pass by value, we can update the SObject fields but still reference the same SObject