Group List with attribute and add another Attribute - java

I have a List of objects. I to assign a color to every object with a similar attibute ie.ParentId.I have done something like so:-
Map<String, String> idToColorMap = new HashMap<String, String>();
int colorIndex = 0;
for (int i = 0; i < myParentList.size(); i++)
{
if (myParentList.size() > 1 && !idToColorMap.containsKey(myParentList.get(i).getParentId())) {
Parent currentParent = myParentList.get(i);
currentParent.setColor(colorPallete[colorIndex]);
idToColorMap.put(currentParent.getParentId(), colorPallete[colorIndex]);
for (int j = i + 1; j < myFinalParentList.size(); j++) {
if (myParentList.get(j).getParentId().equals(currentParent.getParentId())) {
myParentList.get(j).setColor(colorPallete[colorIndex]);
}
}
if (++colorIndex == colorPallete.length) {
colorIndex = 0;
}
} else {
myParentList.get(0).setColor(colorPallete[0]);
idToColorMap.put(myParentList.get(0).getParentId(), colorPallete[0]);
}
}
But with this only the first item in the list with the ParentId is assigned the color and not all the items with the same ParentId

The problem comes from your tests.
// OK for parent[0] but not all other
if (myParentList.size() > 1 && !idToColorMap.containsKey(myParentList.get(i).getParentId())) {
...
}
// Will only set you first parent not all others
else {
myParentList.get(0).setColor(colorPallete[0]);
idToColorMap.put(myParentList.get(0).getParentId(), colorPallete[0]);
}
With your test you can only enter the if if you have not encounter this parentId. But if you have already encountered one then you go to else where you only change parent[0].
You should separate your test.
EDIT :
Here is something that should work (didn't test, maybe some minor correction has to be done). Plus: I didn't understand what is your myFinalParentList so I didn't put it in here. Just add your foreach after my code. if necessary
Map<String, String> idToColorMap = new HashMap<String, String>();
int colorIndex = 0;
String colorPallete = ...;
for (Parent parent : myParentList) {
// if is not in idIdColorMap then I add it
if (!idToColorMap.containsKey(parent.getParentId()) {
idToColorMap.put(parent.getParentId(), colorPallete[colorIndex]);
// increment colorIndex
if (colorIndex + 1 == colorPallete.length) {
colorIndex = 0;
} else {
colorIndex++;
}
}
// Set Parent's Color
parent.setColor(idToColorMap.get(parent.getId());
}

Related

Is there a more concise way of writing repetitive code changing which method is used?

I've written a very repetitive piece of code (as seen below) and I feel that there has to be some way to use a method to make it more concise, but I cannot figure out how.
This is the current code snippet:
if (event.getSource() == firstNameButton) {
inputType = "first name";
for (int i = 0; i < myList.length; i++) {
if (myList[i].getFirstName().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
} else if (event.getSource() == lastNameButton) {
inputType = "last name";
for (int i = 0; i < myList.length; i++) {
if (myList[i].getLastName().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
} else if (event.getSource() == usernameButton) {
inputType = "username";
for (int i = 0; i < myList.length; i++) {
if (myList[i].getUsername().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
} else if (event.getSource() == domainNameButton) {
inputType = "domain name";
for (int i = 0; i < myList.length; i++) {
if (myList[i].getDomainName().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
} else if (event.getSource() == domainExtensionButton) {
inputType = "domain extension";
for (int i = 0; i < myList.length; i++) {
if (myList[i].getDomainExtension().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
}
The only things changing are what inputType gets assigned to, which I would be able to write a method for, but I am also changing what method I apply to myList[i]. Is there a way to write a method with a method parameter?
Assume that myList is an array of class MyList.
Add the following method to class MyList.
public class MyList {
public String getValue(String key) {
return switch (key) {
case "first name" -> getFirstName();
case "last name" -> getLastName();
case "username" -> getUsername();
case "domain name" -> getDomainName();
case "domain extension" -> getDomainExtension();
}
}
}
The above method uses switch expressions which were added in Java 12.
Assume the code in your question is from an actionPerformed method.
Assume that firstNameButton, lastNameButton, etc, are all JButtons.
Then you can assign an appropriate action command to each, for example:
firstNameButton.setActionCommand("first name");
Now your actionPerformed method can be reduced to:
public void actionPerformed(java.awt.event.ActionEvent event) {
String actionCommand = event.getActionCommand();
for (int i = 0; i < myList.length; i++) {
if (myList[i].getValue(actionCommand).equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
}
Alternatively, you can use the stream API:
public void actionPerformed(java.awt.event.ActionEvent event) {
String actionCommand = event.getActionCommand();
java.util.Arrays.stream(myList)
.filter(m -> m.getValue(actionCommand).equals(input))
.findFirst()
.ifPresent(m -> {
returnList[returnLength] = myList[i];
returnLength++;
});
}
Note that method findFirst returns an object of type Optional.
Create an abstraction for extracting data from your object. You need something which accepts argument of type your custom class and return string result, Function will do, but you can create your own as well. Extract the repetition to a method, using the abstraction:
private void myMethod(MyObject[] myList, Function<MyObject, String> valueExtractor, String input) {
for (int i = 0; i < myList.length; i++) {
if (valueExtractor.apply(myList[i]).equals(input)) {
//do required stuff
}
}
}
You can still use if-else to get the correct extractor, but i would suggest to use a Map instead to keep the keys and their respective extraction functions:
Map<String, Function<MyObject, String>> map = Map.of("firstNameButton", MyObject::getFirstName,
"lastNameButton", MyObject::getLastName);
Function<MyObject, String> extractor = map.get(event.getSource());
myMethod(theList, extractor, theInput);
Here is an "Old Dog" approach:
Repeated or nearly repeated sections of code can be often be reduced with arrays and / or Collection Objects, loops, and methods. What parts of the nearly repeated code are the same, and what parts are different?
if (event.getSource() == *********Button) {
inputType = "**********";
for (int i = 0; i < myList.length; i++) {
if (myList[i].get*********().equals(input)) {
returnList[returnLength] = myList[i];
returnLength++;
}
}
I replaced the parts of the O/P code that vary with *********.
I have to make some assumptions here.
The array myList is apparently an array of some sort of Object, with various geter methods that return some sort of Object, probably a String. But, I'll use Bar in this example:
Suppose myList is an array of Foo. The beginning of the code for Foo might look something like this:
public class Foo {
private Bar firstName, lastName, userName, domainName, domainExtension;
You could add this method:
public Bar getNameAttribute (int attributeKey) {
switch (attributeKey) {
case 0:
return firstName;
break;
case 1:
return lastName;
break;
case 2:
...
default:
return null;
break;
}
}
Now, the various ~Button variables are reference types. It's reasonable to assume that, once they are created and initialized, the references will not be changed to point to some other button. In fact, use of event.getSource () == implies that is the case. So, let us use an array to reference them, in addition to referencing them using their individual reference names. I'll assume they are Objects of JButton type:
JButton [] nameButton = { firstNameButton, lastNameButton, userNameButton
, domainNameButton, domainExtensionButton };
String [] eventType = {"first name", "last name", "user name"
, "domain name", "domain extension" };
for (int k = 0; k < nameButton.length; k++) {
if (event.getSource() == nameButton [k] {
for (int i = 0; i < myList.length; i++) {
if (mylList[i].getNameAttribute[k].equals(input)){
returnList[returnLength] = myList[i];
returnLength++;
}
}
break;
}
}
Notes:
Use of switch in the getNameAttribute method assumes references to the various names can be changed. For example, Foo foo1 = new Foo (...); ... foo1.setFirstName (new Bar ("Jones")); If, after creation and initialization, references to all of the names are fixed, the getNameAttribute code can be reduced by using an array of aliases, as was done with the Buttons.

Is there a way to dynamically create a counter if such "month" exists?

I would like to enquire or get some reference as to how can I dynamically create a counter for each month if the exists ? Currently, I am retrieving the dates from a CSV file and store it in an ArrayList, from there I am comparing the dates to check whether if such month exists. If the month exists then "counter++". Afterwards, store the counter in a hashmap. I understand my code currently is an inefficient way of coding. How could I make it better ?
CODE
public HashMap<String, Integer> getDataPoint() {
//My function code
HashMap<String, Integer> numberOfPost = new HashMap<String, Integer>();
int janCounter = 0;
int febCounter = 0;
int marCounter = 0;
int aprCounter = 0;
int mayCounter = 0;
int juneCounter = 0;
int julyCounter = 0;
int augCounter = 0;
int septCounter = 0;
int octCounter = 0;
int novCounter = 0;
int decCounter = 0;
String pattern = "MMM";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
OpenCsvReader reader = new OpenCsvReader();
ArrayList <STPost> STArray = reader.loadST("file_path");
Iterator STitr = STArray.iterator();
while (STitr.hasNext()) {
STPost St = (STPost) STitr.next();
Date retrievedate = St.getTime();
String strDate = sdf.format(retrievedate);
if(strDate.equals("Jan")) {
janCounter++;
}
else if (strDate.equals("Feb")) {
febCounter++;
}
else if (strDate.equals("Mar")) {
marCounter++;
}
else if (strDate.equals("Apr")) {
aprCounter++;
}
else if (strDate.equals("May")) {
mayCounter++;
}
else if (strDate.equals("June")) {
juneCounter++;
}
else if (strDate.equals("July")) {
julyCounter++;
}
else if (strDate.equals("Aug")) {
augCounter++;
}
else if (strDate.equals("Sept")) {
septCounter++;
}
else if (strDate.equals("Oct")) {
octCounter++;
}
else if (strDate.equals("Nov")) {
novCounter++;
}
else if (strDate.equals("Dec")) {
decCounter++;
}
numberOfPost.put("January", janCounter);
numberOfPost.put("Feburary", febCounter);
numberOfPost.put("March", marCounter);
numberOfPost.put("April", aprCounter);
numberOfPost.put("May", mayCounter);
numberOfPost.put("June", juneCounter);
numberOfPost.put("July", julyCounter);
numberOfPost.put("August", augCounter);
numberOfPost.put("September", septCounter);
numberOfPost.put("October", octCounter);
numberOfPost.put("November", novCounter);
numberOfPost.put("December", decCounter);
}
return numberOfPost
}
You can create an array of months and check if value exists there using indexOf method.
String months = "JanFebMarAprMayJunJulAugSepOctNovDec";
Integer idx = months.indexOf(strDate);
Thereafter you can use SimpleDateFormat("MMMM") pattern to put and get it into your map.
if(idx > -1) {
String longDate = new SimpleDateFormat("MMMM").format(retrievedate);
Integer current = numberOfPost.get(longDate);
if (current == null) {
current = 1;
} else {
current += 1;
}
numberOfPost.put(longDate, current);
}
Thereafter, you can use map iterator to display content of map.
You already have a good start. Using a the hash map will make the code much tidier.
You can replace all those if statements and put statements with the code below:
if (!numberOfPosts.containsKey(strDate)) {
numberOfPosts.put(strDate, 0);
}
numberOfPosts.put(strDate, numberOfPosts.get(strDate) + 1);
The if statement will create a dictionary entry if there is not one with the key of strDate. The value of the entry is set to 0.
numberOfPosts.put(strDate, numberOfPosts.get(strDate) + 1)
The line above increments by 1 the dictionary entry with the key of strDate.

Use values from previous row to aggregate values when row missing

I have a whole bunch of rows that contain tax payments.
Each row contains PaymentDueDate.
If row is missing in between PaymentDueDates, I have to use same values from previous row to aggregate for all totals.
In below example, between Row="2" and Row="3", data is missing for months 2015/09, 2015/10, 2015/11, 2015/12, 2016/01, 2016/02.
So, I have to use Row="2" values to use to account for missing rows.
<PaymentChangeMaintenance>
<PaymentChangeMaintenanceTransaction Row="1">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-07-01</PaymentDueDate>
<CityTaxAmount>23.22</CityTaxAmount>
<CountyTaxAmount>32.25</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="2">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2015-08-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
<PaymentChangeMaintenanceTransaction Row="3">
<BuydownSubsidyAmount>0.00</BuydownSubsidyAmount>
<AnnualInterestRate>4.75000</AnnualInterestRate>
<PIAmount>689.79</PIAmount>
<PaymentDueDate>2016-03-01</PaymentDueDate>
<CityTaxAmount>125.25</CityTaxAmount>
<CountyTaxAmount>666.22</CountyTaxAmount>
</PaymentChangeMaintenanceTransaction>
</PaymentChangeMaintenance>
Here is code someone wrote, but it is not clean-looking. I would like to use for-each :/
private void aggregateEscrowPaymountAmounts(List<PaymentChangeMaintenanceFieldsV214Type> fieldsType,
PaymentChangeMaintenance paymentChangeMaintenance, final int numberOfTrialPayments) {
AtomicInteger cnt = new AtomicInteger(1);
Iterator<PaymentChangeMaintenanceFieldsV214Type> fieldsTypeIterator = fieldsType.iterator();
PaymentChangeMaintenanceFieldsV214Type fieldType = fieldsTypeIterator.next();
PaymentChangeMaintenanceFieldsV214Type nextFieldType = null;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
}
LocalDate monthDate = fieldType.getNextPaymentDueDate();
while (cnt.getAndIncrement() <= numberOfTrialPayments) {
PaymentChangeMaintenance tempPaymentChangeMaintenance = createPaymentChangeMaintenanceEscrow(fieldType);
paymentChangeMaintenance.aggregate(tempPaymentChangeMaintenance);
monthDate = monthDate.plusMonths(1);
if (nextFieldType != null) {
LocalDate nextFieldTypeDate = nextFieldType.getNextPaymentDueDate();
if (nextFieldTypeDate.getMonthValue() == monthDate.getMonthValue()) {
fieldType = nextFieldType;
if (fieldsTypeIterator.hasNext()) {
nextFieldType = fieldsTypeIterator.next();
} else {
nextFieldType = null;
}
}
}
}
}
For this certain case you can use a following approach: determine a step - for you it's a month. Then initialize a default value for a case of absence of the value on the next step. Then use some method that will take a next value and default value and depends on a step presence will return one of them
Here is a pseudocode:
List<Item> items;
Item nextItem = items.get(0);
Value step = month;
for (int i = 1; i < items.size(); i++) {
nextItem = getNextItem(items.get(i), nextItem, step);
****
}
Item getNextItem(Item nextItem, Item defaultItem, Value step) {
if (!nextItem.getStepValue().equals(calcNext(step))) {
return defaultItem;
} else {
return nextItem;
}
}
StepValue calcNext(Value step) {
/*some calculations. In your case month increment*/
}

Modifying ArrayList object values from another class

I have two classes: class Creature which contains ArrayList boids, and class Food.
Boids have a few parameters:
Creature(float posX, float posY, int t, int bth, int ah) {
location = new PVector(posX, posY);
vel = new PVector(random(-5,5), random(-5, 5));
acc = new PVector();
type = t;
if (t == 1) { btype = bth; }
else { health = bth; }
if (t == 1) { age = ah; }
else { hunger = ah; }
wdelta = 0.0;
action = 0;
if (btype == 1) { mass = 5.0; }
else { mass = 7.0; }
}
Food class has this method:
void foodtime(ArrayList boids) {
for (int i = 0; i < boids.size(); i++) {
Creature boid = (Creature) boids.get(i);
float distance = PVector.dist(location, boid.location);
if (distance < 0.5) {
bnumadj = i;
count++;
if (count == quantity) {
planet.food.remove(this);
count = 0;
bnumadj = -1;
}
}
}
}
What I'm trying to achieve is that if a boid "eats" the food, their boid type (btype) changes from 2 to 1.
I'm trying to use bnumadj variable to feed it back to the boid in this method:
void boid(ArrayList boids) {
for (int i = 0; i < boids.size(); i++) {
if (i == bnumadj) {
this.btype = 1;
bnumadj = -1;
}
}
}
Where am I going wrong?
This seems like a very convoluted way to do this, so I'm not surprised you're having issues. You're comparing values to indexes, which doesn't make a ton of sense to me.
Instead, try using a simple nested loop to do what you want. You can use an Iterator to make it easier to remove items while iterating.
ArrayList<Creature> boids = new ArrayList<Creature>();
ArrayList<Food> food = new ArrayList<Food>();
//populate ArrayLists
void draw(){
for(Creature boid : boids){
Iterator<Food> foodIter = food.iterator();
while(foodIter.hasNext()){
Food f = foodIter.next();
float distance = PVector.dist(boid.location, food.location);
if (distance < 0.5) {
boid.btype = 1;
foodIter.remove(); //removes the food
}
}
}
//draw the scene
}
I suppose you could move the second iteration using the Iterator inside the Creature type, but the basic idea is this: keep it simple by using an Iterator to remove the Food instead of trying to match indexes.

Add the items from one list to another list in java

I have two arraylists say
ArrayList<BaseItem> normal;
ArrayList<BaseItem> highlighted;
normal = new ArrayList<BaseItem>();
highlighted = new ArrayList<BaseItem>();
what I am doing is I am Iterating through a 3rd list(called MyItems) and adding the items in it called highlight and normal to the above two lists like this.
for (Iterator<BaseItem> iterator = MyItems.iterator(); iterator.hasNext();) {
BaseItem itemtype = iterator.next();
if (itemtype.isHighlight()) {
highlighted.add(itemtype);
}
else{
normal.add(itemtype);
}
}
So my question is I want to add every 5th and 6th item of the highlited list to the list called normal .i.e elements like 5,6,11,12,17,18 and so on
and also I want to add every 6th and 7th item of normal list to highlighted list i.e 6,7,13,14 and so on.
so now my highlighted and normal lists will contain the items like this
Highlighted -> highlighted1,highlighted2,highlighted3,highlighted4,normal6,normal7 highlighted7,highlighted8.highlighted9,highlighted10,normal13,normal14 and so on
Normal -> Noraml1,normal2,normal3,normal4,normal5,highlighted5,highlighted6,normal7,normal8,normal9,normal10,normal11,normal12,highlighted11,highlighted12 and so on
Any help is always appreciated,
Thanks
If I understand, use a counter when after 5 and 6 insert in your list, add in normal list instead of highlighted list
Try this:
int highAdded = 0;
int normalAdded = 0;
for (Iterator<BaseItem> iterator = MyItems.iterator(); iterator.hasNext();) {
BaseItem itemtype = iterator.next();
if (itemtype.isHighlight()) {
highAdded++;
if (highAdded == 5) {
normal.add(itemtype);
} else if (highAdded == 6) {
normal.add(itemtype);
highAdded = 0;
} else {
highlighted.add(itemtype);
}
}
else{
normalAdded++;
if (normalAdded == 6) {
highlighted.add(itemtype);
} else if (normalAdded == 7) {
highlighted.add(itemtype);
normalAdded = 0;
} else {
normal.add(itemtype);
}
}
}
EDIT
I write this code:
public class StackOverFlowSample {
public static void main(String [] args) {
List<String> lst = new ArrayList<String>();
List<String> lstHigh = new ArrayList<String>();
List<String> lstNormal = new ArrayList<String>();
lst.add("highlighted01");
lst.add("highlighted02");
lst.add("highlighted03");
lst.add("highlighted04");
lst.add("highlighted05");
lst.add("highlighted06");
lst.add("highlighted07");
lst.add("highlighted08");
lst.add("highlighted09");
lst.add("highlighted10");
lst.add("highlighted11");
lst.add("highlighted12");
lst.add("highlighted13");
lst.add("highlighted14");
lst.add("highlighted15");
lst.add("highlighted16");
lst.add("normal01");
lst.add("normal02");
lst.add("normal03");
lst.add("normal04");
lst.add("normal05");
lst.add("normal06");
lst.add("normal07");
lst.add("normal08");
lst.add("normal09");
lst.add("normal10");
lst.add("normal11");
lst.add("normal12");
lst.add("normal13");
lst.add("normal14");
lst.add("normal15");
lst.add("normal16");
int highAdded = 0;
int normalAdded = 0;
for (Iterator<String> iterator = lst.iterator(); iterator.hasNext();) {
String itemtype = iterator.next();
if (itemtype.startsWith("highlighted")) {
highAdded++;
if (highAdded == 5) {
lstNormal.add(itemtype);
} else if (highAdded == 6) {
lstNormal.add(itemtype);
highAdded = 0;
} else {
lstHigh.add(itemtype);
}
}
else{
normalAdded++;
if (normalAdded == 6) {
lstHigh.add(itemtype);
} else if (normalAdded == 7) {
lstHigh.add(itemtype);
normalAdded = 0;
} else {
lstNormal.add(itemtype);
}
}
}
String result = "HIGHLIGHTED ARRAY: ";
for (String curr : lstHigh) {
result += curr + ", ";
}
System.out.print(result);
result = "NORMAL ARRAY: ";
for (String curr : lstNormal) {
result += curr + ", ";
}
System.out.print(result);
}
}
The output is:
HIGHLIGHTED ARRAY: highlighted01, highlighted02, highlighted03, highlighted04, highlighted07, highlighted08, highlighted09, highlighted10, highlighted13, highlighted14, highlighted15, highlighted16, normal06, normal07, normal13, normal14,
NORMAL ARRAY: highlighted05, highlighted06, highlighted11, highlighted12, normal01, normal02, normal03, normal04, normal05, normal08, normal09, normal10, normal11, normal12, normal15, normal16,
Tell me if it's OK ;)

Categories

Resources