Converting an ArrayList<HashMap> into a multidimensional List - java

I have an ArrayList of HashMap elements that has a format of Category, Activity and Time. I.E.
{CATEGORY=Planning, ACTIVITY=Bills, TIME=5}
{CATEGORY=Planning, ACTIVITY=Bills, TIME=7}
{CATEGORY=Planning, ACTIVITY=Meetings, TIME=10}
{CATEGORY=Resources, ACTIVITY=Room1, TIME=15}
....
Take note of the CATEGORY/ACTIVITY pair that is repeated as that can happen in the List
I need to be able to convert this List into a multidimensional one. The best way I can think of for how this List needs to look is by writing some pseudocode...please see that at the bottom of the post.
I've thought of several different approaches on how to implement this but I'm quite frankly stuck and frustrated at how to do this. I've thought of taking the inefficient approach of looping through the ArrayList several times in outer and inner loops but I know that wouldn't be good coding practice.
Any suggestions on how I can implement this conversion so I can loop like in the pseudocode below?
For CATEGORY in CATEGORIES {
CategoryTime = 0
Display Category Header
For ACTIVITY in ACTIVITIES {
Activity Time = 0
For TIME_RECORD in ACTIVITY
Add time to activity total time, category total time & grand total
}
Display Activity Total
}
Display Category Total
}
Display Grand Total and rest of information...
Edit
I appreciate all the feedback given for this problem and it appears that really the best way to go is to enhance a class that the ArrayList of HashMap elements is a member of.
I've put in a vote to close this question as has another person as it's too localized. I would appreciate it if some of you other developers would follow suit to close the question. I would delete it but I can't at this point because there are answers to the question.

I would write a class that looks like so:
public class Planner
{
Map<Category, Collection<Planner> details;
String activity;
long time;
}
public enum Category
{
PLANNING,RESOURCES,ETC;
}
Then you should be able to do the following:
for(Category current: Planner.getDetails().keySet())
{
CategoryTime = 0
Display Category Header
Activity Time = 0
for(Planner currentPlanner : planner.getDetails().get(current))
{
currentPlanner.getActivity();
Activity Time += currentPlanner.getTime();
}
}

The problem you'll have with using the Collections API, besides a poor abstraction, is that you'll have to store many Activities for a given Category. If Category is the key, then you're forced to have a List<Activity> as the value in the Map. And if you query for a given Category, your work isn't done: you have to iterate over the List<Activity> to find the one you want. How will you know?
It's not a Map; it's a multi-map.
I agree with the folks who recommend a class. It's far better, and not that much more work. Better abstractions and more information hiding are usually better for you and your clients.
public class Activity {
private Category category;
private Duration duration; // You want to encapsulate value and units together, right?
// I can see sequencing information that could be useful. Your whole Planner seems to be in need of work.
}
I think your idea of time units is poorly done, too. I can't tell if TIME=10 means 10 hours, days, weeks, months, years, decades - you get the point. Units matter a lot, especially in this context. You would not want people to add times together that used different units.

Related

How to get cumulative amount total from list of Map

In one of my case I get the input like below which has a list inside with list of Maps.
List<Map<String, String>> actAllSavAccDetLists = test1Page.getAllSavingsAccountsDetails();
// returns like this
[
{Savings=Account ****2623, Current Balance=$22000.00, Annual Rate=7.77%, Transfer=Make a Transfer, Ellipses=...},
{Savings=Account ****5678, Current Balance=$11000.00, Annual Rate=2.22%, Transfer=Make a Transfer, Ellipses=...}
]
Now I need to find the total balance for the user, i.e.; adding up all the current balance from the Map inside a list.
Say in this case, adding $22000.00 + $11000.00 to give the result as $33000.00 in a total_bal variable.
You can easily use java stream map->reduce to make that:
Double totalBalance = actAllSavAccDetLists.stream()
.map(e -> e.get("Current Balance").substring(1))
.map(e -> new BigDecimal(e))
.reduce(BigDecimal.ZERO, BigDecimal::add);
The java-compatible way to do it is not to have this map at all. Java is nominally typed, and really likes its types. a Map<String, String> is not an appropriate data type here.
First, make a class that represents a savings account.
Next, instead of having a List<Map<String, String>>, have a List<SavingsAccount>.
Finally, sum up the balances.
Making a class
Looks like it would be something along the lines of:
#lombok.Value
public class SavingsAccount {
String accountId;
int balance; // in cents
double rate; // might need to be BigDecimal
}
You'll need to festoon it up to become a proper java class (the fields need to be final and private, getters and setters nee dto be there, a constructor, equals, toString, etcetera). I'm using lombok here (disclaimer: I'm one of the developers), but you can also use a java16 record, or use your IDE to generate all this stuff.
Converting that mess into instances of SavingsAccount
Converting a map that contains for example a mapping Transfer = Make a Transfer into an instance of this rather strongly suggests your input is coming from some bizarre source. You'll know better than we do how to convert it. You can now localize all the various required conversions and open questions into a single place. For example, what should happen if, say, map.get("CurrentBalance") doesn't exist, or returns "€10000.00"?
This boils down to "How do I convert the string "$22000.00" into the integer 2200000", or "How do I convert "7.77%" into a double", which is not difficult, and an unrelated question; if you're having trouble with it, I'm sure it's been answered a million times on SO already so you'll find it swiftly with a web search.
Summing it up
That's trivial:
List<SavingsAccount> accounts = ...;
int sum = accounts.stream().mapToInt(SavingsAccount::getBalance).sum();
This streams all the accounts, extracts just the balance from each, and then sums the entire stream into a single number.
I don't want to make that class
Well, it's a bit silly to do things in ways no sane java programmer would ever do. If you're trying to learn, you'll be learning the wrong ways of work. If you're trying to deliver freelance work, you'll get negative reviews. If you're "in a hurry", taking shortcuts now will just cost you triple later on. You do want to make that class.
If you insist on being stubborn, the same techniques can be used, just, with the order all jumbled up. You can stick the code that extracts the balance in that mapToInt call:
.mapToInt(s -> extractBalanceFromThisBizarroMap(s))
and then just write static int extractBalanceFromThisBizarroMap(Map<String, String> s) yourself.
But don't do that.

Create a country with specific values from a pre-determined list

Background
I'm currently working on an Android application which asks the user a question. At the moment I'm creating the modules for asking the questions. Right now I'm working on a topography module, which will be able to ask the user all kinds of questions about a certain country that will be shown to them.
Problem
For this module I will need a list of all the countries in the world. I currently have a Country class that has a String[] array that has all the countries English names in it (±200). I also want a few other properties in the Country class, such as their capitals, provinces and the translations for them. All of these properties should be selected from a predetermined list. This list should also be rather flexible, so that it in the future I can easily add new properties to them.
The problem I'm currently having is that I'm not quite sure how to create such a list. I've had a couple of ideas but all of them seem faulty, cumbersome or they just plain don't work in Java. Here is an example of a few of my ideas:
Create a multidimensional array that holds all the countries values which can then be easily selected with predefined indices. This is something that I often use when programming in PHP, because it can hold all kinds of different types. You can also define the keys (indices) of the array in PHP, but this doesn't work in Java.
Create an enum for all the countries and use the int associated with the specific country to select values from a capital/province array. This is a bit too cumbersome for my liking, it would require me to create an enormous array everytime I would want to add another property/question for the country (making a mess of the Country class in my opinion).
Create classes for all the properties I want Country to have. This has the advantage that I could expand on these classes further with more information (such as giving a Capital class properties such as: amount_of_residents), and has the advantage of perhaps creating a sophisticated translation class. I'm just wondering if this is the most efficient/logical way to proceed?
I feel that there should be some very nice solution for this problem I'm facing, but for the love of me I just can't figure it out. If you guys have any idea as what would be the best option (I'm currently leaning to option 3), or give me another solution to the problem that's more efficient, it would be greatly appreciated.
Note: I haven't added any code, because I didn't feel it would be necessary. If anyone would like to see some code I would be happy to provide it.
I believe you should go with the last approach, it should be something like the below sample code P.S
class Country {
String countryName;
String capital;
int noOfResidents;
List<String> provinces;
//getter & setters for them
public void setCountryName(String countryName)
{
this.countryName=countryName;
}
//And so on & forth
}
class SetCountryDetails {
public static void main(String[] args){
Map<String, Country> countryData = new HashMap<String, Country>();
//Using a map facilitates easier fetch for the countries. You can just
//provide the key of the country, for an instance to fetch the data for Germany
//just write countryData.get("Germany");
Country countryOne = new Country();
countryOne.setCountryName("Germany");
countryData.put("Germany", countryOne);
Country countryTwo = new Country();
countryOne.setCountryName("India");
countryData.put("India", countryTwo);
}
}
This approach enables you to add or delete a property to the Country class anytime without much hassle.
I'm not sure I totally understand what the issue really is. Basically you seem to have a domain object called Country that has a number of properties, and you seem to want to extend dynamically? Perhaps some code would help to solve your problem.
As per my understanding from your question, You need to use the list of Countries and respective properties of those Countries. And those properties need to be flexible in future to add/remove. For this you can maintain the list of countries and related properties in a property file or an XML file, which can be flexible in future to add/remove properties if required. If my understanding is wrong then make it clear for me. :)

Organizing workout info with hashmaps and arrays

I'm looking to create a java program that will store a workout with each lift and reps performed. But I'm not exactly sure how to organize the data structure. I was thinking to use a hashmap to store everything with the hashcode being the date performed. So something performed december 24, 2013 would be stored at 122413. The element I would want to store there would be like an array of arrays, with each array displaying the lift and each following element would alternate between the reps performed and weight. Here's a visual example of that.
arr = [["bench press",10,185,9,195,8,205],["shoulder press",10,95,8,95,6,95],...]
So if I wanted the reps and weight performed for my second set of bench press it would output like:
You performed arr[0][1] reps of arr[0][2] for arr[0][0]
---
You performed 10 reps of 185 for bench press
-----
I know this can be done in python, but I'm not sure that it's available in java?
I'm having issues implementing as from what I've found the datatypes of an array all need to be the same type (no string AND int), which is actually okay because these numbers don't really have a numerical value and will just be displayed. But I'm also a little stuck on getting an array stored in a hashmap and building an array of arrays.
So, my question: is this a doable implementation for what I'm trying to accomplish? Or is there a better way to go about organizing this? I'd like to keep the data organized by date as I showed earlier if possible. Any help or suggestions would be wonderful. Thanks!
I'd probably go with creating custom data structures to model your scenario. For example.
Set class with a weight property and a reps property.
Exercise class with a name property and a collection of Sets.
Workout class with a collection of Exercises and a date property for when the workout was done.
That way, if you wanted to extend it to include food you eat that day, you could either add it to the workout, or probably a better option would be to compose another class of a Workout and food eaten.
That way you open the possibility to draw correlations between how well you trained on a certain day with what you eat.
-- I'm a C# developer and I haven't touched Java before so apologies if the Syntax or the types aren't correct --
public class Set {
public Set()
{
this._weight = 0;
this._reps = new ArrayList<int>();
}
private BigDecimal _weight;
private List<int> _reps;
// implement public properties / methods
}
public class Exercise {
public Exercise()
{
this._name = "";
this._sets = new ArrayList<Set>();
}
private String _name;
private List<Set> _sets;
// implement public properties / methods
}
public class Workout {
public Workout(Date workoutDate)
{
this._date = workoutDate;
this._exercises = new ArrayList<Exercise>
}
private Date _date;
private List<Exercise> _exercises;
// implement public properties / methods
}
Then you'd be able to store a List and order them by Date using a custom implementation of Comparator<Workout>

Writing code with multiple Class Methods and String Arrays

So what I am trying to do is create a code that lists music artists names using user input.
It has to have multiple classes so I will have a main class, and a class for each decade of music.
Music.java
six.java
seven.java
eight.java
In these classes I need to create string arrays that contain artist names, and be able to generate the entire list once prompted.
To give a better idea of how the code will run it would go something like:
Choose a decade of music:
70's
Choose a genre of music:
Rock
Choices are: Rolling Stones, Talking Heads, etc.
That's all I need it to do but I'm getting stuck on what to put in the main class "music.java" to get it to read the other classes and furthermore how to write the decade classes.
I understand I don't have much to offer you guys here but any help would be appreciated.
In general terms, you need a class in this rough form:
public class Artist
{
public int decade
public string genre
}
Then some code to use it:
... code to retrieve some kind of collection (e.g. an array or list), of artists as Artist objects (you'll need to do this by retrieving the artist data from a database)
... code to iterate through the collection to do what you want with it:
I would only have a class named Band and a container class for all bands named BandRegister. The Band would hold a Set of values representing the decade, which are added using associateWithDecate(int decade) method:
Class BandRegister:
Map<Integer, Set<Band>) decadeMap = new HahMap...
public addBand(band);
{
//define logic for adding the decade and band to decadeMap
}
Class Band:
Set<Integer> decades = ...
public associateWithDecate(int decade)
{
//add decade to decades if not already included
}
In Main:
BandRegister breg = new BandRegister();
Band stones = new Band("Rolling Stones");
stones.associateWithDecate(60);
stones.associateWithDecate(70);
stones.associateWithDecate(70);
stones.associateWithDecate(90);
stones.associateWithDecate(0);
stones.associateWithDecate(10);
breg.addband(stones);
That way, you can get a listing of decades for each band and also in the register you can get a listing of bands for each decade

Java HashMap indexed on 2 keys

I want to create a HashMap in java for users with preferences. This would be easy to do in a database, but unfortunately I can't use a database. What I need is a way to find a user by name in the HashMap, and to find all the users with a certain interest (e.g. golf). If I delete a user, then all their interests should be deleted.
Anyone know a nice way to make this data structure?
I would suggest you create your own data structure for holding the information. Inside that class you could have two HashMaps storing the relevant information. Then write your own methods to insert and delete a user.
This way you have control over the insert/delete-operations while being able to query each attribute separately.
Do you know you really need to have a second index. You may find that a search of every user is fast enough, unless you have millions of users.
The following example takes 51 micro-second to scan 1,000 users. It takes 557 micro-seconds to scan 10,000 users.
I wouldn't suggest optimising the collection until your know whether it would make a difference.
import java.util.*;
import java.io.*;
public class TestExecutor {
public static void main(String[] args) throws IOException {
Map<String, User> users = new LinkedHashMap<String, User>();
generateUsers(users, 1000, 0.1);
// warmup.
int count = 10000;
for(int i=0;i< count;i++)
getAllUsersWithInterest(users, Interest.Golf);
long start = System.nanoTime();
for(int i=0;i< count;i++)
getAllUsersWithInterest(users, Interest.Golf);
long time = System.nanoTime() - start;
System.out.printf("Average search time %,d micro-seconds%n", time/ count/1000);
}
private static Set<User> getAllUsersWithInterest(Map<String, User> users, Interest golf) {
Set<User> ret = new LinkedHashSet<User>();
for (User user : users.values()) {
if (user.interests.contains(golf))
ret.add(user);
}
return ret;
}
private static void generateUsers(Map<String, User> users, int count, double interestedInGolf) {
Random rand = new Random();
while(users.size() < count) {
String name = Long.toString(rand.nextLong(), 36);
EnumSet<Interest> interests = rand.nextFloat() < interestedInGolf
? EnumSet.of(Interest.Golf) : EnumSet.noneOf(Interest.class);
users.put(name, new User(name, interests));
}
}
static class User {
private final String name;
private final Set<Interest> interests;
User(String name, Set<Interest> interests) {
this.name = name;
this.interests = interests;
}
}
enum Interest {
Golf
}
}
Simplest solution is to use a Commons Collection MultiKeyMap even if it is lacking generics.
...Check this thread too genericized-commons-collection
it seems like you could use something like a bi-directional map to implement something like this. check out http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/BiMap.html for some doco.
although it doesnt give you exactly what you need in the question, its half the way there.
This may be overkill for your needs, but I don't know how complex and speed sensitive your needs are, so I'll throw it out there...
Have you considered looking at an in-memory (or even local disk based like SQLite) database to handle your data. Doing so would allow you to store your data in a way that allows much more power in how you search/index your data, without many of the costs of writing your own code.
Just put the users in an ArrayList, and walk over it till you found the one(s) you need. Give each user a set of interests. Once you get enough users that it takes too long, sort them.
Once that takes too long, take a look at the distribution of interests. If you have a low number of different ones, store them in a bitmap. If you have a limited set of combinations of interests, store them separately and give a user one of these.
Start simple, computers are fast. But hide the implementation, so you can change it.
[hmm, getting negative votes for this]. Look at the question: you'll need a lot of users before this code is as slow as a database. (on current hardware, at least a few hundred thousand)
I would implement the following
HashMap which include the user as key and the value could be any object which includs the userpreferences. The user preferences would include a list of interest for example.
And an additional HashMap with an interest as key and a list of users who are interested in this.
When you delet a user, you can get all the interest he has and delete the user name from the interest HashMap list.
When the interest HashMap list is empty you can delet the interest from the HashMap.
Take care, when 2 or more users have the same interest. You can not delet the interest when only one user is deleted.
The downside is, that you will have redundant informations.
You could use 2 HashMaps. But searching only trough preferences could be complicated.
HashMap <String,Hashmap> users;
//save data
//create new user
HashMap <String,String> prefs;
//save prefs
prefs.put(pref1,value1);
prefs.put(pref2,value2);
//save user
users.put(user1,prefs);
//get data
String x = users.get(user1).get(pref1);
Maybe you don't need this solution anymore, but many people still have same problems.

Categories

Resources