Add up the column values in while loop if it comes repetedly - java

I am creating a table from ajax and the getting of values using a while loop:
while (rstdb.next()) {
rstdb.getInt(1)+"~"+ rstdb.getInt(2);
}
In my while loop my rstdb.getInt(1) will be 2,2,2,2,2,3,3...... and second values rstdb.getInt(2) are 10,20,30,40,50,10,20,.....
I need to sum up the values specific to 2 and values specific to 3 seperate.
ie,
It means 10+20+30+40+50 =150 for 2 and 10+20 =30 for 3.
It may contain single values also for example it may have 4,5,5,6,7,7....
How can I do that?
I need something like:
while (rstdb.next()) {
rstdb.getInt(1)+"~"+ rstdb.getInt(2)+"~"+sum;
}
The variable sum should contain the sum up value.

Use map for this. You can have a map which should be mapping the specific number with sum of it's corresponding value.
int c1, c2;
Map<Integer, Integer> sum = new HashMap<>();
while (rstdb.next()) {
c1 = rstdb.getInt(1);
c2 = rstdb.getInt(2);
if(sum.containsKey(c1)) {
sum.put(c1, sum.get(c1) + c2);
// ^ will return current sum of second column
} else {
sum.put(c1, c2);
}
rstdb.getInt(1)+"~"+ rstdb.getInt(2)+"~"+sum.get(c1);
}

You can use an integer to integer map:
Map<Integer, Integer> integerMap = new HashMap<>();
while (rstdb.next()) {
int column1 = rstdb.getInt(1);
int column2 = rstdb.getInt(2);
if (integerMap.containsKey(column1)) {
int currentSum = integerMap.get(column1);
integerMap.put(column1, currentSum + column2);
} else {
integerMap.put(column1, column2);
}
}
Edit: to print out the map, you can use loop through the entrySet of the map:
for (Map.Entry entry : integerMap.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}

Related

Java - How to implement a data structure that contains the number of clicks that were recorded on each domain AND each subdomain under it

I have a problem statement as described below:
Write a function that takes this input as a parameter and returns a data structure containing the number of
clicks that were recorded on each domain AND each subdomain under it.
For example, a click on "mail.yahoo.com" counts toward the totals for "mail.yahoo.com", "yahoo.com", and "com".
(Subdomains are added to the left of their parent domain. So "mail" and "mail.yahoo" are not valid domains.
Note that "mobile.sports" appears as a separate domain near the bottom of the input.)
Below is the input data:
String[] counts = {
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk"
};
Below is the expected output:
calculateClicksByDomain(counts) =>
com: 1345
google.com: 900
stackoverflow.com: 10
overflow.com: 20
yahoo.com: 410
mail.yahoo.com: 60
mobile.sports.yahoo.com: 10
sports.yahoo.com: 50
com.com: 5
org: 3
wikipedia.org: 3
en.wikipedia.org: 2
m.wikipedia.org: 1
mobile.sports: 1
sports: 1
uk: 1
co.uk: 1
google.co.uk: 1
I tried to write a solution for above problem statement:
Map<String, Integer> calculateClicksByDomainMap = new HashMap<>();
for(int i = 0; i < counts.length; i++) {
String[] seperateClickCountsAtComma = counts[i].split("\\,");
for(int j = 0; j < seperateClickCountsAtComma.length; j += 2) {
String clickCounts = seperateClickCountsAtComma[j];
String domain = seperateClickCountsAtComma[j+1];
calculateClicksByDomainMap.put(domain, Integer.parseInt(clickCounts));
}
}
for(Entry<String, Integer> domainCounts : calculateClicksByDomainMap.entrySet()) {
String domainName = domainCounts.getKey();
Integer domainCount = domainCounts.getValue();
splitStringOnOccurenceOfDot(domainName);
//System.out.println(domainName + " " + domainCount);
//String test[] = domainName.split("\\.");
//System.out.println(test[0] + "=======" + test[1] + "-----");
}
public static String splitStringOnOccurenceOfDot(String domainName) {
if(!domainName.contains(".")) {
return domainName;
}
String[] subdomain = domainName.split("\\.");
domainName = subdomain[1];
System.out.println(domainName + "===============" );
return splitStringOnOccurenceOfDot(domainName);
}
However, I'm not sure how to split the string using recursion.
Can anyone help me what is the efficient way to write code in order to get the expected output?
I there a way to solve it using recursion?
Thank you for your time.
The Map needs to ConcurrentHashMap, so that it allows concurrent updates.
First for loop with nesting can call the recursive method like below, might not need another for loop:
Map<String, Integer> calculateClicksByDomainMap = new ConcurrentHashMap<>();
for (final String count : counts) {
String[] separateClickCountsAtComma = count.split("\\,");
for (int j = 0; j < separateClickCountsAtComma.length; j += 2) {
Integer clickCount = Integer.parseInt(separateClickCountsAtComma[j]);
String domain = separateClickCountsAtComma[j + 1];
calculateClicksByDomainMap.put(domain, clickCount);
splitStringOnOccurenceOfDot(domain.substring(domain.indexOf(".")+1), clickCount, calculateClicksByDomainMap);
}
}
Rather than returning a value, recursion add/update map itself.
public static void splitStringOnOccurenceOfDot(String domainName, Integer domainCount, Map<String, Integer> calculateClicksByDomainMap) {
if(calculateClicksByDomainMap.containsKey(domainName)) {
Integer newCount = calculateClicksByDomainMap.get(domainName) + domainCount;
calculateClicksByDomainMap.put(domainName, newCount);
} else {
calculateClicksByDomainMap.put(domainName, domainCount);
}
if(domainName.contains(".")) {
splitStringOnOccurenceOfDot(domainName.substring(domainName.indexOf(".")+1), domainCount, calculateClicksByDomainMap);
}
}

Hashmap - iterating and getting the ouput printed too many times

In the below code contains_All hashmap is putting the key and value for each iteration.
After for loop I am clicking on next button again putting the name and state in hashmap
so my hashmap should contain all the values for every page.
But when i am printing the hashmap
I am getting 4 lists
The key and value of 1 page.
The key value of 2 pages along with 1 page
3.The key value of 3 page along with 1 and 2
The key value of 4 pages along with previous all
NOw when I am iterating the map I am getting too many values as it is printing 1, 2,3 and4
But I want only the 4 which contains all
public static validate()
{
get value();
while (utils.isElementDisplayed(next)) {
utils.waitForElement(next, 20);
utils.click(next);
getValue();
}
public getValue{
for (int i = 0; i < allRows.size(); i++) {
names = ds_name.get(i).getText();
seName = ds_server.get(i).getText();
state = ds_state.get(i).getText();
String names_seName = name_ds.concat("_" + serverName_ds);
containsAll.put(names_seName, state);
}
System.out.println(containsAll);
Iterator it = containsAll.entrySet().iterator();
while (it.hasNext()) {
Map.Entry ent = (Map.Entry) it.next();
System.out.println("-----------------------------------------------------------");
System.out.println(ent.getKey() + "= " + ent.getValue());
Reporter.log("-----------------------------------------------------------");
Reporter.log(ent.getKey() + "= " + ent.getValue());
}
}
In order to display The key value of 4 pages along with previous all you need to move the displaying code block outside the for loop. In this case it is the block of code starting with Iterator it = containsAll.entrySet().iterator();.
Complete code sample:
public static validate() {
get value();
while (utils.isElementDisplayed(next)) {
utils.waitForElement(next, 20);
utils.click(next);
getValue();
}
public getValue {
for (int i = 0; i < allRows.size(); i++) {
names = ds_name.get(i).getText();
seName = ds_server.get(i).getText();
state = ds_state.get(i).getText();
String names_seName = name_ds.concat("_" + serverName_ds);
containsAll.put(names_seName, state);
System.out.println(containsAll);
}
Iterator it = containsAll.entrySet().iterator();
while (it.hasNext()) {
Map.Entry ent = (Map.Entry) it.next();
System.out.println("-----------------------------------------------------------");
System.out.println(ent.getKey() + "= " + ent.getValue());
Reporter.log("-----------------------------------------------------------");
Reporter.log(ent.getKey() + "= " + ent.getValue());
}
}
The reason this works and the original code doesn't is because you fill the hashmap and print it as well. In doing so you print page 1, then page 1 & 2, then page 1,2 & 3 and finally page 1,2,3 & 4. Moving the print outside the for loop only prints the finished hashmap.

How efficiently we can get the required output from the list in java?

CircuitID Department Hours
--------------------------------
Circuit A Electricity 60
Circuit A Hydel 70
Circuit B Hydel 30
Circuit C Electricity 40
Circuit B Electricity 80
Circuit C Hydel 50
Circuit A Electricity 70
Now i have to create one list which will have records on following criteria:
In each circuit id i need to get the record with highest hours but if duplicate hours are present than i need to take the one with Electricity department.
Result for the above result should be like below:
Circuit A Electricity 70
Circuit B Electricity 80
Circuit C Hydel 50
Let me know how can i iterate effectively and in most efficient way to get the final list using java 8/ java.
The code i wrote is not at all working perfectly and my approch was shown below:
for (int i = 0; i < circuitList.size(); i++) {
for (int j = 0; j < circuitList.size(); {
if (circuitList.get(i).getCircuitId().equals(circuitList.get(j).getCircuitId()) && i != j) {
if (circuitList().get(i).getHours() == circuitList().get(j).getHours()) {
if (circuitList().get(i).getDepartment().equals(“Electricity”) {
newList.add(circuitList().get(i));
}
// some more conditions on getHours
Circuit class is having pojo objects with getter setters of this three objects.
public class Circuit {
String circuitID;
int hours;
String department;
}
You can do it by toMap() collectors with merge function.
Map<String, Circuit> map = circuitList
.stream()
.collect(Collectors.toMap(Circuit::getCircuitID, Function.identity(),merge));
and merge function is:
BinaryOperator<Circuit> merge = (left, right) -> {
if (left.hours > right.hours) return left;
else if (left.hours < right.hours) return right;
//if (left.department.equals("Electricity")) return left;
if (right.department.equals("Electricity")) return right;
return left;
};
and get final result:
List<Circuit> result = new ArrayList<>(map.values());
First write a custom comparator to check for highest hours and evaluate duplicate hours situation to take the one with Electricity department:
Comparator<Circuit> cmp = new Comparator<Circuit>() {
#Override
public int compare(Circuit o1, Circuit o2) {
int compare = Integer.compare(o1.getHours(), o2.getHours());
if(compare==0) { // equal hours so check for department
// the element with 'Electricity' value must seem to be have max value
if(o1.getDepartment().equals("Electricity")) {
compare = 1;
}
if(o2.getDepartment().equals("Electricity")) {
compare = -1;
}
}
return compare;
}
};
Then group by circuitId attribute with Collectors.groupingBy(Circuit::getCircuitId, and find max hours with the help of custom comparator above Collectors.maxBy(cmp):
Map<String, Optional<Circuit>> resultMap = circuitList.stream().collect(
Collectors.groupingBy(Circuit::getCircuitId, Collectors.maxBy(cmp)));
Collection<Optional<Circuit>> result = resultMap.values();
result.forEach(x -> System.out.println(x.get().getCircuitId() + " " + x.get().getDepartment() + "\t" + x.get().getHours()));
public static Map<String, Circuit> getMaxHours(final List<Circuit> circuitsList) {
final Map<String, Circuit> mappedCircuitsById = new HashMap<String, Circuit>();
for (final Circuit circuit : circuitsList) {
if (!mappedCircuitsById.containsKey(circuit.getCircuitID())) {
mappedCircuitsById.put(circuit.getCircuitID(), circuit);
} else {
final Circuit existingMax = mappedCircuitsById.get(circuit.getCircuitID());
if (circuit.getHours() > existingMax.getHours()) mappedCircuitsById.put(circuit.getCircuitID(), circuit);
else if (circuit.getHours() == existingMax.getHours()) {
if (circuit.getDepartment().equals("Electricity")) mappedCircuitsById.put(circuit.getCircuitID(), circuit);
else if (existingMax.getDepartment().equals("Electricity")) mappedCircuitsById.put(circuit.getCircuitID(), existingMax);
}
}
}
return mappedCircuitsById;
}
Create a map where the key of the map is the circuitID and the value is the Circuit object which meets the "max hours" requirements. Iterate over the elements of the list and and update the map accordingly to store the new "max hours" Circuit object
We have to group by CircuitID first and write custom comparator to filter based on our requirement. It can be done as shown below:
List<Circuits> filteredList = new ArrayList<>();
list.stream().collect(Collectors.groupingBy(Circuits::getCircuitID)).forEach((key, value) -> filteredList.add(compare(value)));
private static Circuits compare (List<Circuits> list) {
Circuits circuits = null;
for (Circuits c : list) {
if (null == circuits) {
circuits = c;
}
if (c.getHours() > circuits.getHours()) {
circuits = c;
} else if (c.getHours() == circuits.getHours()) {
circuits = c.getDepartment().equalsIgnoreCase("Electricity") ? c : circuits;
}
}
return circuits;
}

find the most and least used string in an ArrayList

I am having trouble finding the most and least used String in an ArrayList. The program should go through a file of Strings and count how many multiple strings there are in the list. Then print the least and most used name in the list. The ArrayList Part is finished. It is just finding the most and least common name I am having trouble with. I have no idea how to even start with it. This is what I have found online but it is not working.
Map<String, Integer> dogNames = new HashMap<>();
for (Dog dog : dogs) {
Integer value = dogNames.get(dog);
if (value == null) {
value = 0;
}
value++;
dogNames.put(dog.getName(), value);
}
int leastCommon = Integer.MAX_VALUE;
String leastCommonName = null;
for (String name : dogNames.keySet()) {
int value = dogNames.get(name);
if (value < leastCommon) {
leastCommon = value;
leastCommonName = name;
}
}
System.out.println("Least common (" + leastCommon + ") is " + leastCommonName);
The problem with your code seems to be in this line:
Integer value = dogNames.get(dog);
Your map holds dog names (String), but you are getting the entry for the Dog, which does not exist! Thus, value stays 0 even if you've seen that name before. If you fix this, you code should work.
Instead of your loop for searching the least common name, you could also define a custom Comparator based on the counts in the map and then use Collections.min and Collections.max:
Comparator<Dog> comp = new Comparator<Dog>() {
#Override
public int compare(Dog o1, Dog o2) {
return Integer.compare(dogNames.get(o1.getName()), dogNames.get(o2.getName()));
}
};
System.out.println("least " + Collections.min(dogs, comp));
System.out.println("most " + Collections.max(dogs, comp));
With Java 8, you can make it even shorter, using Comparator.comparing:
List<Dog> dogs = ...
Map<String, Integer> dogNames = new HashMap<>();
dogs.forEach(dog -> dogNames.put(dog.getName(), dogNames.getOrDefault(dog.getName(), 0) + 1));
Comparator<Dog> comp = Comparator.comparing(d -> dogNames.get(d.getName()));
System.out.println("least " + Collections.min(dogs, comp));
System.out.println("most " + Collections.max(dogs, comp));
Or even shorter, using Collections.frequency instead of building your own map, and using that to compare. Note, however, that this will be wasteful if the list is very long, since this will search the list each time anew instead of caching the counts in the map.
List<Dog> dogs = ...
Comparator<Dog> comp = Comparator.comparing(d -> Collections.frequency(dogs, d.getName()));
System.out.println("least " + Collections.min(dogs, comp));
System.out.println("most " + Collections.max(dogs, comp));
Your code should look something like this...
Map<String,int> frequencyOfDogNames = new HashMap<String,int>();
for(String dogName:dogNames) {
if(frequencyOfDogNames.contains(dogName)) {
continue;
}
frequencyOfDogNames.put(dogName, Collections.frequency(dogs, "dogName"));
}
This will give you the map of all the names with the occurrences.
Now we should loop thought the map to see which one are the max and min...
int leastCommon = Integer.MAX_VALUE;
int mostCommon = 0;
String leastCommonName, mostCommonName;
int occurrence;
for(String dogName: frequencyOfDogNames.keySet()) {
occurrence = frequencyOfDogNames.get(dogName);
if(leastCommon > occurrence){
leastCommon = occurrence;
leastCommonName = dogName;
}
if(mostCommon < occurrence){
mostCommon = occurrence;
mostCommonName = dogName;
}
}

Addition of ArrayList values having same Date

I am having a sorted ArrayList like-
List<DD_Details> list = new ArrayList<DD_Details>();
list.add(new DD_Details(26/05/2014,3000.00));
list.add(new DD_Details(26/08/2014,6000.00));
list.add(new DD_Details(26/08/2014,2000.00));
DD_Details Class is -
class DD_Details {
private Date ddSubmissionDate;
private Double amount;
public DD_Details(Date n, Double s) {
this.ddSubmissionDate = n;
this.amount = s;
}
public Date getDdSubmissionDate() {
return ddSubmissionDate;
}
public void setDdSubmissionDate(Date ddSubmissionDate) {
this.ddSubmissionDate = ddSubmissionDate;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public String toString() {
return "ddSubmissionDate: " + this.ddSubmissionDate + "-- amount: "
+ this.amount;
}
}
i just want to add amount values of the same date and store in a new ArrayList.
I tried below code but it is not working properly.
for (int i = 0; i < list.size(); i++) {
Double amt = 0.0;
Date date1 = list.get(i).getDdSubmissionDate();
for (int j = i + 1; j < list.size(); j++) {
if (date1.equals(list.get(j).getDdSubmissionDate())) {
amt = amt + list.get(j).getAmount() + list.get(i).getAmount();
} else {
amt = list.get(i).getAmount();
}
}
list1.add(new DD_Details(date1, amt));
}
Please give me some hint to get it done. Thanks in Advance.
You can use next solution instead:
List<DD_Details> list = new ArrayList<DD_Details>();
List<DD_Details> list1 = new ArrayList<DD_Details>();
list.add(new DD_Details(new Date(2014, 5, 26), 3000.00));
list.add(new DD_Details(new Date(2014, 8, 26), 6000.00));
list.add(new DD_Details(new Date(2014, 8, 26), 2000.00));
for (DD_Details currentEl : list) // iterate over 'list'
{
DD_Details existingElement = null;
for (DD_Details el1 : list1) // find element in 'list1' with the same date
{
if (el1.getDdSubmissionDate().equals(currentEl.getDdSubmissionDate()))
{
existingElement = el1;
break;
}
}
if (existingElement == null) // if element is not found in 'list1' then add current element to list
{
list1.add(currentEl); // or list1.add(new DD_Details(el.getDdSubmissionDate(), el.getAmount()))
}
else // if element is found, then increase amount
{
existingElement.setAmount(existingElement.getAmount() + currentEl.getAmount());
}
}
// 'list1' contains what you need
In the inner for, when you are adding the values for a particular date, there is an error in the else part. You try to iterate through the list for a given date and add all the values until the date is different. Once you reach this condition, you get inside the else and set the sum to be the amount of the first element of this given date, therefore you are overriding the sum you had calculated. Moreover, for every new element with the same date, you are adding the amount of the first date, which means that if there are 4 elements of the same date, you will be adding 3 times the first amount.
What you should do, is get the amount for that given date before entering the second loop. One final consideration, is that you are going to get different amounts for different dates because imagine you have 3 elements with the same date, with the loop you are using, you will start with the first one, get the amount of the 3 elements added, then go to the second and get the amount of the second and third added, and finally move to the last one and create a third element with the amount of only the third element. Therefore, you should create a third variable which I called k, and store the last j value that contained the same date, to then add it to i and avoid iterating through an element with a date you already processed:
for (int i = 0; i < list.size(); i++) {
Double amt = list.get(i).getAmount();
Date date1 = list.get(i).getDdSubmissionDate();
int k = 0;
for (int j = i + 1; j < list.size(); j++) {
if (date1.equals(list.get(j).getDdSubmissionDate())) {
amt = amt + list.get(j).getAmount();
k = j;
}
}
list1.add(new DD_Details(date1, amt));
i += k++;
}
Your dates should be String literals. The way you've written them they will be ints and all equal to 0.
The obvious solution would be to build a Map of dates to amounts (instead of a list) and after adding all the entries iterating the map to build your list. Something like:
Map<Date, Double> amountPerDate = new HashMap<>();
List<Date> dates = ...;
List<Double> amounts = ...; // wherever those may come from
for(int i = 0; i < dates.size(); i++) {
Double currentAmount = amountPerDate.get(dates.get(i));
double amount = currentAmount == null ? 0 : currentAmount;
amountPerDate.put(dates.get(i), amount + amounts.get(i));
}
List<DD_Details> details = new ArrayList<>();
for(Entry<Date, Double> e : amountPerDate) {
details.put(new DD_Details(e.getKey(), e.getValue());
}
// optionally, you may Collections.sort(details); the list
In your DD_Details class, consider using a primitive double instead of a boxed Double.
I guess that your problem is in your second for-loop in the else-part of the if-statement. Even if you have dates which match you will have some dates which will not match. Thus you set back your amount the the amount of i.
You should add:
System.out.println("The dates are equal. New amount is: " + amt);
to your if-statement and:
System.out.println("Dates do not match. " + amt);
Now you should see that you add the amount the correct way but you reset it in the else part several times.

Categories