How to traverse an ArrayList of Objects - java

I have an ArrayList of custom made Users. The list is already sorted by manager.My goal is to go through the list by manager and add each user to the body of an email depending on their expiration date.
A User is basically built like this from the database. All necessary accessors/mutators are present:
id|fName|lName|...|manager
Go through the users and notify the manager if the user is expiring:
To: Manager
Expiring in 10 days
<User>
<User>
Expiring in 30 days
<User>
StringBuilder body = new StringBuilder();
ArrayList<Users> contractors;
Date today = cal.getTime();
...
if(contractors != null && contractors.size() > 0){
for(int i = 0; i < contractors.size(); i++){
if(i+1 > contractors.size()){
//do something to avoid outOfBounds and still access last item in the list
}else{
if (contractors.get(i+1).getManager() != null){
if(manager.equals(contractors.get(i+1).getManager())){
if(today.compareTo(contractor.getExpiration()){
//build body of email
}
}
}
sendEmail(manager, body.toString());
}else{
//new manager
body.equals(""); // reset email for next run
}
}
After the email is sent I want to move on to the next set of users based on manager. My problem is that I'm having trouble with the logic behind traversing the array by manager and then resetting everytime for each new manager. I'm thinking that I need another for loop?
What's the best way to do this? thanks
Edit
When implemented this way:

I would do it something like this:
if (contractors != null) {
String currentManager = null;
for (User contractor : contractors) {
String contractorManager = contractor.getManager();
if (!contractorManager.equals(currentManager) {
// a new manager
if (currentManager != null) {
sendEmail(body.toString());
body.setLength(0);
}
currentManager = contractorManager;
}
//build body of email ...
}
// send the email for the last manager
sendEmail(body.toString());
}

Iterate the list of Users and add them to a Map keyed by manager with a Set of employees per manager. Something like,
if (contractors != null && contractors.size() > 0) {
Map<String, Set<Users>> map = new HashMap<>();
for (Users contractor : contractors) {
String manager = contractor.getManager();
if (manager == null) {
manager = contractor.getName();
}
Set<Users> employees = map.get(manager);
if (employees == null) {
employees = new HashSet<>();
map.put(manager, employees);
}
employees.add(contractor);
} // now you can iterate the keySet and then each manager's employees like
for (String manager : map.keySet()) {
Set<Users> employees = map.get(manager);
for (Users u : employees) {
// ...
}
}
}

You should go for a "foreach" loop on contractors, more info here
another example here

If they are already sorted, you can take this approach (I'm using "ManagerObject" to represent the return type of Users.getManager() - replace with the actual class name):
StringBuilder body = new StringBuilder();
ManagerObject currentManager = null;
for (Users contractor : contractors) {
if (currentManager != null && !(contractor.getManager().equals(currentManager)) {
sendEmail(body.toString());
body.equals("");
}
currentManager = contractor.getManager();
// Add stuff to the body for this contractor
}
If the call to Users.getManager() is computationally expensive for some reason, this can be rejiggered to only set the currentManager upon a change in value

Related

optimize nested for loops within nested if statements

I am trying to optimize this code. The only optimization I can think of is to a return or break statement after applyOfferChanges(...) inside the second if condition.
Any ideas?
void applyFavoriteChangesToMerchantStore(){
List<Merchant> favoriteMerchantsList = FavoriteMerchantStore.getInstance().getFavoriteMerchantsList();
if(favoriteMerchantsList != null && !favoriteMerchantsList.isEmpty()) {
List<Merchant> storeMerchantList = MerchantStore.getInstance().getMerchantList();
for (Merchant storeMerchant : storeMerchantList) {
for (Merchant favoriteMerchant: favoriteMerchantsList){
if(TextUtils.equals(storeMerchant.getId(), favoriteMerchant.getId())){
//merchant match found
//set merchant favorite status
storeMerchant.setFavoriteMerchant(favoriteMerchant.getFavoriteMerchant());
//set offer favorite status
applyOfferChanges(favoriteMerchant.getOffferList(),
storeMerchant.getOffferList());
}
}
}
}
}
It all depends on things you haven't shown us. How big are the lists, what exactly does TextUtils.equals? Assuming, it's android.text.TextUtils, the answer is clear: Instead of two nested loops (complexity O(m*n)), use a HashMap (complexity O(m+n)).
Instead of
for (Merchant storeMerchant : storeMerchantList) {
for (Merchant favoriteMerchant: favoriteMerchantsList) {
if(TextUtils.equals(storeMerchant.getId(), favoriteMerchant.getId())) {
....
}
do
Map<String, Merchant> favoriteMerchantMap = new HashMap<>();
for (Merchant favoriteMerchant : favoriteMerchantsList) {
favoriteMerchantMap.put(favoriteMerchant.getId(), favoriteMerchant));
}
for (Merchant storeMerchant : storeMerchantList) {
Merchant favoriteMerchant = favoriteMerchantMap.get(storeMerchant.getId());
if (favoriteMerchant != null) {
....
}
I think you could optimize this with java-8.
If I'm not mistaken, your code does not set favorites to null if they cannot be found anymore.
This should do the same as your original code, but in a more java-8 way:
void applyFavoriteChangesToMerchantStore(){
// take list of favorite merchants
List favoriteMerchantsList = FavoriteMerchantStore.getInstance().getFavoriteMerchantsList();
// if any favorites found, we gotta do something with them
if(favoriteMerchantsList != null && !favoriteMerchantsList.isEmpty()) {
// take list of all merchants
List<Merchant> storeMerchantList = MerchantStore.getInstance().getMerchantList();
// convert those into a map with the ids as keys
Map<String, Merchant> storeMap = storeMerchantList.stream().collect(Collectors.toMap(Merchant::getId, merchant -> merchant));
// set the favorite for each merchant
favoriteMerchantsList.forEach(favoriteMerchant -> {
// if each favorite is guaranteed to be in the list of storeMerchantList, this causes no null result
Merchant storeMerchant = storeMap.get(favoriteMerchant.getId());
//set merchant favorite status
storeMerchant.setFavoriteMerchant(favoriteMerchant.getFavoriteMerchant());
//set offer favorite status
applyOfferChanges(favoriteMerchant.getOffferList(), storeMerchant.getOffferList());
});
}
}
If you want to reset (set to null) the merchants currently matching no favorites, your code could look like this:
void applyFavoriteChangesToMerchantStore(){
// take list of favorite merchants
List favoriteMerchantsList = FavoriteMerchantStore.getInstance().getFavoriteMerchantsList();
Map<String, Merchant> favMap = null;
if(favoriteMerchantsList == null) {
// if no favorites found, creating an empty map
favMap = new HashMap<>();
} else {
// convert list into a map with the ids as keys
favMap = favoriteMerchantsList.stream().collect(Collectors.toMap(Merchant::getId, merchant -> merchant));
}
// take list of all merchants
List<Merchant> storeMerchantList = MerchantStore.getInstance().getMerchantList();
// set the favorite for each merchant
storeMerchantList.forEach(storeMerchant -> {
if (favMap.containsKey(storeMerchant.getId()))
{
// get the favorite
Merchant favoriteMerchant = favMap.get(storeMerchant.getId());
//set merchant favorite status
storeMerchant.setFavoriteMerchant(favoriteMerchant.getFavoriteMerchant());
//set offer favorite status
applyOfferChanges(favoriteMerchant.getOffferList(), storeMerchant.getOffferList());
} else {
//set merchant favorite status
storeMerchant.setFavoriteMerchant(null);
// cannot call applyOfferChanges, because no favoriteMerchant (or change this as you wish)
}
});
}
}
Nothing of this is tested though, I hope they work, feel free to respond, if it helped.

java delete all items in dynamodb

Im trying to delete all items in my table in dynamodb but it does not work.
try {
ScanRequest scanRequest = new ScanRequest().withTableName(table);
ScanResult scanResult = null;
do {
if (Check.nonNull(scanResult)) {
scanRequest.setExclusiveStartKey(scanResult.getLastEvaluatedKey());
}
scanResult = client.scan(scanRequest);
scanResult.getItems().forEach((Item) -> {
String n1 = Item.get("n1").toString();
String n2 = tem.get("n2").toString();
DeleteItemSpec spec = new DeleteItemSpec().withPrimaryKey("n1", n1, "n2", n2);
dynamodb.getTable(table).deleteItem(spec);
});
} while (Check.nonNull(scanResult.getLastEvaluatedKey()));
} catch (Exception e) {
throw new BadRequestException(e);
}
n1 is my Primary partition key
n2 is my Primary sort key
The best approach to delete all the items from DynamoDB is to drop the table and recreate it.
Otherwise, there are lot of read capacity and write capacity units being used which will cost you.
Dropping and recreating the table is the best approach.
PREAMBLE: While a scan operation is expensive, I was needing this answer for initialising a table for a test scenario (low volume). The table was being created by another process and I needed the test scenario on that table, I could therefore not delete and recreate the table.
ANSWER:
given:
DynamoDbClient db
static String TABLE_NAME
static String HASH_KEY
static String SORT_KEY
ScanIterable scanIterable = db.scanPaginator(ScanRequest.builder()
.tableName(TABLE_NAME)
.build());
for(ScanResponse scanResponse:scanIterable){
for( Map<String, AttributeValue> item: scanResponse.items()){
Map<String,AttributeValue> deleteKey = new HashMap<>();
deleteKey.put(HASH_KEY,item.get(HASH_KEY));
deleteKey.put(SORT_KEY,item.get(SORT_KEY));
db.deleteItem(DeleteItemRequest.builder()
.tableName(TRANSACTION_TABLE_NAME)
.key(deleteKey).build());
}
}
To delete all the items from the table first you need to perform scan operation over the table which will results you an scanoutcome. Using the iterator loop over the sacnoutcome with the primary key and it's primary key value.This will be one of the approach to delete all the items from the table. Hope that this code will work you. Thanks
Table table = dynamoDB.getTable(your_table);
ItemCollection<ScanOutcome> deleteoutcome = table.scan();
Iterator<Item> iterator = deleteoutcome.iterator();
while (iterator.hasNext()) {
your_table.deleteItem("PrimaryKey", iterator.next().get("primary key value"));
}
//May be we can make it look generic by reading key schema first as below
String strPartitionKey = null;
String strSortKey = null;
TableDescription description = table.describe();
List<KeySchemaElement> schema = description.getKeySchema();
for (KeySchemaElement element : schema) {
if (element.getKeyType().equalsIgnoreCase("HASH"))
strPartitionKey = element.getAttributeName();
if (element.getKeyType().equalsIgnoreCase("RANGE"))
strSortKey = element.getAttributeName();
}
ItemCollection<ScanOutcome> deleteoutcome = table.scan();
Iterator<Item> iterator = deleteoutcome.iterator();
while (iterator.hasNext()) {
Item next = iterator.next();
if (strSortKey == null && strPartitionKey != null)
table.deleteItem(strPartitionKey, next.get(strPartitionKey));
else if (strPartitionKey != null && strSortKey != null)
table.deleteItem(strPartitionKey, next.get(strPartitionKey), strSortKey, next.get(strSortKey));
}

Retrieving information about a contact with Google People API (Java)

I am using an example of recently released Google's People API from here. I have extended a sample a bit to display additional information about the contact such as an email address and a phone number. The code that should do the job is presented below.
public class PeopleQuickstart {
...
public static void getPersonInfo(Person person){
// Get names
List<Name> names = person.getNames();
if(names != null && names.size() > 0) {
for(Name personName: names) {
System.out.println("Name: " + personName.getDisplayName());
}
}
// Get email addresses
List<EmailAddress> emails = person.getEmailAddresses();
if(emails != null && emails.size() > 0) {
for(EmailAddress personEmail: emails) {
System.out.println("Email: " + personEmail.getValue());
}
}
// Get phone numbers
List<PhoneNumber> phones = person.getPhoneNumbers();
if(phones != null && phones.size() > 0) {
for(PhoneNumber personPhone: phones){
System.out.println("Phone number: " + personPhone.getValue());
}
}
}
public static void main(String [] args) throws IOException {
People service = getPeopleService();
// Request 120 connections.
ListConnectionsResponse response = service.people().connections()
.list("people/me")
.setPageSize(120)
.execute();
// Display information about your connections.
List<Person> connections = response.getConnections();
if (connections != null && connections.size() > 0) {
for (Person person: connections){
getPersonInfo(person);
}
} else {
System.out.println("No connections found.");
}
}
}
I am testing this program with my contact list and I can successfully obtain a list of people along with the name fields. However, I cannot get values for email addresses and phone numbers (lists are always null), although I do have these values set in my contact list (verified through Gmail->Contacts). What am I missing?
Ok, problem solved. It looks like Google's documentation is a bit misleading (well, it has just been released;)). When I try to fetch my contacts using people.connections.list (see here) there are several query parameters that can be set. However, for the requestMask parameter it is stated that "Omitting this field will include all fields" which is not the case (at least did not work for me). Therefore, one has to explicitly specify which fields to be returned in the response. The modified code is given below. I wish Google people would clarify this point a bit.
public class PeopleQuickstart {
...
public static void main(String [] args) throws IOException {
People service = getPeopleService();
// Request 120 connections.
ListConnectionsResponse response = service.people().connections()
.list("people/me")
.setPageSize(120)
// specify fields to be returned
.setRequestMaskIncludeField("person.names,person.emailAddresses,person.phoneNumbers")
.execute();
// Display information about a person.
List<Person> connections = response.getConnections();
if (connections != null && connections.size() > 0) {
for (Person person: connections){
getPersonInfo(person);
}
} else {
System.out.println("No connections found.");
}
}
}

TreeMap<DateTime, Object> is not sorting

I have TreeMap using the Joda DateTime object and is does not seem to be sorting here is the definition:
TreeMap<DateTime, HolderAnswer> dateTimeTreeMap = new TreeMap<DateTime, HolderAnswer>();
I added in the values as follows (I'm just using a generic sql statement here);
//then get previously selected answers to move to the top of the list
String sql = "Select ActionDT, RecID, TextID, Text, Value from Foo";
Cursor c = DataBaseConnector.query(sql);
if (c != null) {
if (c.moveToFirst()) {
do {
HolderAnswer answer = null;
boolean valueAlreadyIn = false;
DateTime dt = formatter.parseDateTime(c.getString(c.getColumnIndex("ActionDT")));
//we will be adding in the options in the next section, setting to null for now.
answer = new HolderAnswer(c.getInt(c.getColumnIndex("RecID")),c.getInt(c.getColumnIndex("TextID")),null,count,c.getString(c.getColumnIndex("Text")));
//////////////////////////////////////////////////////////////
Iterator<Entry<DateTime, HolderAnswer>> it = dateTimeTreeMap.entrySet().iterator();
while (it.hasNext()) {
Entry<DateTime, HolderAnswer> pairs = it.next();
HolderAnswer tempAnswer = (HolderAnswer) pairs.getValue();
DateTime tempDateTime = (DateTime) pairs.getKey();
//if answers match, transfer over options
if (answer.getTextID() == tempAnswer.getTextID()) {
valueAlreadyIn = true;
}
}
if (!valueAlreadyIn) {
dateTimeTreeMap.put(dt,answer);
}
//////////////////////////////////////////////////////////////////
//count++;
} while(c.moveToNext());
c.close();
c = null;
}
}
When I print out the values, they don't seem to be sorted, they come out in no discernable pattern. Even doing:
dateTimeTreeMap.descendingMap();
Does nothing. Am I missing something?
The descendingMap() method is used to return a reverse order view of the mappings contained in this map so it looks like you're forgetting to assign the sorted map to the original one.
dateTimeTreeMap = dateTimeTreeMap.descendingMap();

How to sort Name of Screen in twitter?

Here i'm able to get User Screen names and printing with the below code,but how can i sort those name alphabatically.
Twitter twitter = (Twitter) request.getSession().getAttribute("twitter");
String name = (String) request.getSession().getAttribute("name");
long cursor = -1;
IDs ids = twitter.getFollowersIDs(name, cursor);
do {
for (long id : ids.getIDs()) {
User user = twitter.showUser(id);
out.println(user.getName());
}
} while ((cursor = ids.getNextCursor()) != 0);
This is my code where i'm getting names,how can i sort names.Thank for your help.
Actually a Comparator may be more than you need, I got mixed up with your previous question.
You can simply collect the names themselves in a list and then sort, e.g.:
...
final List<String> names = new LinkedList<String>();
do {
for (...) {
...
names.add(user.getName());
}
} while (...);
Collections.sort(names)
If you inspect names, it will now be sorted.

Categories