How to format map data by their keys - java

I'm trying to format the data inside my HashMap according to their key.
I have a loop which prints data in the following format
icon: "rain"
windBearing: 239
ozone: 339.89
precipType: "rain"
humidity: 0.82
moonPhase: 0.98
windSpeed: 7.37
summary: "Light rain starting in the evening."
visibility: 16.09
cloudCover: 0.62
pressure: 1011.49
dewPoint: 1.26
time: 08-03-2016 00:00:00
temperatureMax: 8.09
All of this data is stored in a HashMap with key (for example) icon and value "rain".
How can I format all of this data according to their keys? I tried something like this
private Map formatter(Map data) {
String tmp;
for(int i = 0; i < data.size(); i++) {
if(data.containsKey("temperatureMax")) {
tmp = String.format("%s c TEST", data.get("temperatureMax"));
data.put("temperatureMax", tmp);
}
}
return data;
}
I thought something like this would format 8.09 to simply 8, but it didn't do anything. (I attempted to do what the answer here How to update a value, given a key in a java hashmap? states)
This is where I acquire the data.
public Map dailyReport() {
FIODaily daily = new FIODaily(fio);
//In case there is no daily data available
if (daily.days() < 0) {
System.out.println("No daily data.");
} else {
System.out.println("\nDaily:\n");
}
//Print daily data
for (int i = 0; i < daily.days(); i++) {
String[] value = daily.getDay(i).getFieldsArray();
System.out.println("Day #" + (i + 1));
for (String key : value) {
System.out.println(key + ": " + daily.getDay(i).getByKey(key));
dailyData.put(key, daily.getDay(i).getByKey(key));
formatter(dailyData);
}
System.out.println("\n");
}
return dailyData;
}

You should iterate through your map keys using the keySet() function of Map
for (String name:data.keySet()) {
if (name.equals("temperatureMax")) {
//Do your formatting
}
}

Related

Visualizating incorrect dada using the stream filter in Java

I have a csv file of the stock exchange I am taking data from, reading it and printing it under certain conditions. One of the conditions under which I must display them is to display the lowest value of a share of each share. My code only shows the first record of each of the three stocks, and does not show the lowest value of these stocks. Where am I going wrong in my filtering using the filter?
My code
private static void smallestPriceByStock(List<String> stocks) throws ParseException {
List<StockPrice> stockPrices = new ArrayList<>();
HashSet<String> stock = new HashSet<>();
SimpleDateFormat sdfOriginal = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfNovaData = new SimpleDateFormat("dd/MM/yyyy");
try {
for (String s : stocks) {
String[] array = a.split(",");
String name = array[0];
String date = array[1];
Date dataOriginal = sdfOriginal.parse(date);
float fechamento = Float.parseFloat(array[2]);
long volume = Long.parseLong(array[3]);
StockPrice stockPrice = new StockPrice(nome, dataOriginal, price, volume);
stockPrices.add(stockPrice);
Stock st = new Stock(name);
st.addStockPrice(stockPrice);
stock.add(st.getNome());
}
System.out.println("Menores fechamentos");
List<Cotacao> cotas = new ArrayList<>();
double smallestValue = 0;
for(String a : acao) {
for (Cotacao c : cotacoes) {
if (c.getNome().contains(a)) {
smallestValue = cotacoes.stream()
.filter(x -> x.getNome() == a)
.mapToDouble(x -> x.getValue()).summaryStatistics().getMax();
System.out.println("Stock: " + c.getNome() + ", " + "Price: " + smallestValue + ", " + "Date: " + sdfNovaData.format(c.getData()));
break;
}
}
}
for(Cotacao cotacao : cotas){
System.out.println(cotacao.getNome());
}
System.out.println();
} catch (UnsupportedOperationException | ParseException e) {
throw new UnsupportedOperationException("calculaMenorFechamentoPorAcao não implementado", e);
}
}
A little sampe of the csv file
Acao,Data,Fechamento,Volume
OGXP3,2013-01-01,4.38,0
OGXP3,2013-01-02,4.76,45904000
OGXP3,2013-01-03,4.90,38143400
PETR4,2013-01-02,19.69,30182600
PETR4,2013-01-03,20.40,30552600
PETR4,2013-01-04,20.43,36141000
PETR4,2013-01-07,20.08,28069600
VALE5,2013-01-01,40.87,0
VALE5,2013-01-02,42.60,18515700
VALE5,2013-01-03,42.09,15001800
VALE5,2013-01-04,41.36,26351900
You are making this more complicated that it needs to be. The common pseudo code for finding lowest value is:
set lowestValue to null
for each value
if lowestValue == null || value < lowestValue
lowestValue = value
As you have multiple values to look for, each identified by the stock name, you define lowest_value as Map<String, BigDecimal> where the key is the stock identifier. Once you have processed each line in the input data, the map contains the lowest value for each stock. There is no need for nested loops, as everyting is done during the single pass. Once the you have populated the map, you can do the printing in a separate single loop over the map data.

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);
}
}

Restart observable based on its emitted values with RxJava

I have an observable which I want to emit Integer values, but if one of the emitted values is negative, I want the observable to emit values again with 1 second delay between emissions until there's no negative values.
I found this answer Repeat/Resubscribe to Observable with condition based on emitted item(s) and I don't really like it because it uses recursion which may slow a device down (depending on how many attempts it'd take to get the proper results).
Is there any other (proper) way of doing that? I also don't know how to set a delay to each emission except for the first one.
Here's what I have now:
getObservable().subscribe(valueList -> {
for (Integer value : valueList) {
Log.d("TAG", "value: " + value);
}
});
private Observable<List<Integer>> getObservable() {
return Observable.fromCallable(() -> {
List<Integer> list = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt(12) - 1);
}
return list;
}).flatMap(valueList -> {
for (int i = 0; i < valueList.size(); i++) {
if (valueList.get(i) < 0) {
Log.d("TAG", "Negative value = " + valueList.get(i) + ", index = " + i);
return getObservable().delay(1, TimeUnit.SECONDS);;
}
}
return Observable.just(valueList);
});
}

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

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());
}

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