Java MAP assistance - java

First off, I've only recently started to use Java, so what might seem obvious to others may not appear so to me.
I'm trying to implement a Quiz application and one of the stipulations is that I read the questions from an external file and store the questions in a MAP structure.
I've looked into this and it appears that a MAP stores a key and a value...
Am I right in thinking that I can store an idetifier as the key and then the rest of the information as the value, even though the rest of it consists of 4 elements of two differing data types (2 ints, a string and an array of strings)?
If my assumtion is correct, how would I implement that, as any documentation I have found resembles the following:
HashMap<Integer, String> questionMap = new HashMap<Integer, String>();
Any assistance or nudges in the right direction are greatly appreciated.
The Question class currently consists of (I've remover the getters and setters to save space on here:
public class Question {
public int identifier;
public String type;
public String question;
public String[] options;
public int answer;
}

First create a class to hold your question information, then use it for the values in your Map, e.g.:
HashMap<Integer, Question> questionMap = new HashMap<Integer, Question>();

the rest of it consists of 4 elements of two differing data types (2 ints, a string and an array of strings)?
This sounds like an Object that you'd want to write your own class for
public class Data {
int id: // optional
int a, b;
String c;
String[] d;
}
Then your Map would be of the type <Integer, Data>, and I would suggest a TreeMap if you want ordered questions

Am I right in thinking that I can store an idetifier as the key and
then the rest of the information as the value, even though the rest of
it consists of 4 elements of two differing data types (2 ints, a
string and an array of strings)?
No, both key and value have to be a of a single data type.
What you usually would do in that case is create your own data structure that encapsules your data:
public class Question {
private int id;
private int score;
private String question;
// Constructor, Getters & Setters
//....
}
Then you can use that dataType as a Value
Map<Integer, Question> questionMap = new HashMap<Integer, Quesiton>();

Related

Have to display the number of times an element has been added in my map JAVA

I've created a TreeMap with products.
And I want to count the number of times they repeat themselves, but have no clue what to code. Any hints? (I expect no code, just suggestions)
private static Map<Integer, String> shoppingCart() {
Map<Integer, String> result = new TreeMap<>();
result.put(1, "sausage");
result.put(2, "sausage");
result.put(3, "soup");
result.put(4, "egg");
result.put(5, "egg");
result.put(6, "tomato");
result.put(7, "sausage");
return result;
}
I was thinking about adding a counting variable, but still it doesn't fix the repeating problem.
Maybe not the best approach, but without modifying what you already have, you could use another map to store the products as keys and the quantity as the value for those keys:
Map<Integer, String> result = shoppingCart();
Map<String, Integer> productQuantities = new HashMap<>();
result.values().forEach(value ->
productQuantities.put(value,productQuantities.getOrDefault(value, 0) + 1));
To print the resulting map:
productQuantities.forEach((key, value) -> System.out.println(key + ":" + value));
I created a TreeMap with products, and i want to count the number of times they repeat themselves
Probably a different type of Map with keys representing items and values representing the corresponding count would be more handy. Something like:
NavigableMap<String, Integer> countByItem
Note: in order to access methods of the TreeMap like ceilingKey(), floorKey(), higherEntry(), lowerEntry(), etc. which are not defined in the Map interface you need to use NavigableMap as a type.
And it might make sense to make the item to be a custom object, instead of being a String. That would guard you from making typo, and it provides a possibility to gives useful behavior to Item
public class Item {
private int id;
private String name;
// constructor, getters, equals/hashCode, ect.
}
That's how map of items can be updated using Java 8 method merge(), which expects a key, a value and a function responsible for merging the old value and the new one:
NavigableMap<Item, Integer> countByItem = new TreeMap<>(Comparator.comparingInt(Item::getId));
countByItem.merge(new Item(1, "sausage"),1, Integer::sum);
countByItem.merge(new Item(1, "sausage"),1, Integer::sum);
countByItem.merge(new Item(2, "soup"),1, Integer::sum);
If you don't feel very comfortable with Java 8 functions, instead of merge() you can use combination of methods put() & getOrDefault():
Item sausage = new Item(1, "sausage");
countByItem.put(sausage, countByItem.getOrDefault(sausage, 0) + 1);
I can only guess at your goal. In your Map <Integer, String>, what does the Integer represent? Product number? Quantity? Sequence number? Something else?
If the Integer represents quantity, you have it backwards. It should be Map <String, Integer>. In a Map<X,Y>, the X represents the key. A Map allows fast lookup by the key. The Y is the value -- the information you want to find for a particular key, if the key is in the Map.
For example, if you want to add "sausage", you want to check if it is in the Map. If it isn't, put it into the Map with quantity 1. If it is, retrieve it and update the quantity.
If the Integer represents a sequence number (1st item, 2nd item, 3rd item, ...), you don't need a Map. Consider using an array or a data structure that preserves order, such as a List.
However, using an array or List still leaves you with the problem of how find how many of each item are in the list, when duplicates are allowed, as they are in your problem. To solve that, consider a Map<String, Integer> where the Integer (map value) is the quantity, and the String (map key) is the product name.
If I were doing this, I'd create classes to allow me to glue together related information. Here is part of a hypothetical example, which might be more realistic than you need:
public class Product {
private int upc; // product code, often represented with bar code
private Decimal price;
private String description;
private String shortDescription;
private ProductClass prodClass; // department, taxable, etc.
// etc. -- add needed fields, or remove irrelevant
// constructors, getters, setters,
Override .equals and .hashcode in Product. You use the UPC for those.
If you use implements Comparable<Product>, you have the possibility of using binary search, or a search tree.
public class Receipt {
private Decimal total;
private Decimal taxableTotal;
private Map <Product,Integer> shoppingCart; // Product, Quantity
// etc.
When each item is scanned, you can lookup the Product in the Map, and add it if not found, or update the quantity if found, as in the previous answers.

dynamic arrays with more that one column

I need to store different types of DATA inside one same "array" associated to a key (or an ID) in my android application, and I'm wondering if there's a way to create HashMaps (or equivalent dynamic arrays) that have more than one column of content. Like this for example.
HashMap<Integer, String, LatLng, Marker> myHashMap = new HashMap<Integer, String, LatLng, Marker>();
Thanks in advance for any idea.
private class Row {
public Integer i;
public String s;
public LatLng ll;
public Row(Integer i, String s, LatLng ll) {
this.i = i;
this.s = s;
this.ll = ll;
}
}
List<Row> rows = new ArrayList<Row>();
This is semi pseudo code but I think you get the idea
Adding new Rows to the list can be done with
rows.add(new Row(new Integer(1), "a string", new LatLng(51.448495, 5.470877));
Editing a row can be done with
rowIndex = 3;
Row row = rows.get(rowIndex);
row.i = 2; //give a new value
//etc
Edit: replaced pseude code with real code
map is just a key and value so HashMap makes very little sense
Java does not let you define data structured this way. A collection of type Class A should have hold only instance of Class A or its sub type.
EDIT: From the data you have provided seems like you want to process each row from a database table. Most appropriate data structure for it is to have a class with fields that correspond to a database table.
When you fetch a row from the a result set just create an instance of this class.
Class mysqlTuple
{
public Integer id;
public String message;
public LatLng latitude;
public Marker longitude;
}
mysqlTupe [] mysqlTable = new mysqlTupe [];
It depends a lot on what you are trying to achieve
One option is to keep 3 different maps:
Map<String, Integer>
Map<String,Marker>
Map<String,LatLng>
Another option is to make a:
Map<String,Object>
However you will have to 'instanceof' to check the real type, which is not a best practice.

Order values by separate string

Sorry about the non-descriptive title, I couldn't think of a way to explain it better short of 100 words. What I would like to be able to do is sort a list of strings into "boxes" based on a string associated with the main string and an array of strings "order".
For my current setup I am using a HashMap to store the string and it's associated "place-in-the-order" string.
I am aware that my explanation is truly crap so I have made an image which I hope will explain it better:
The variables are initialised as follows:
private final String[] order = new String[] {"Severe", "Warning", "Info"};
private final Box[] boxes = new Box[] {new Box(1), new Box(2), new Box(3), new Box(4)};
private final Map<String, String> texts = new HashMap<String, String>();
texts.put("Server on fire!", "Severe");
texts.put("All is good!", "Info");
texts.put("Monkeys detected!", "Warning");
texts.put("Nuke activated!", "Severe");
This shouldn't be too hard to implement but the only way I can think of doing it is by using 3 loops which seems a bit wasteful and would be slow if there was large numbers of any of the inputs.
Here is some example code which will hopefully show what I have come up with so far and perhaps explain the problem, I have not tested it and don't have an IDE handy so have probably overlooked something.
Set<Box> usedBoxes = new HashSet<Box>();
for(String curOrder : order) {
for (String text : texts) {
if (texts.get(text).equals(order)) {
for (Box box : boxes) {
if (!usedBoxes.contains(box)) {
box.setText(text);
usedBoxes.add(box);
break;
}
}
}
}
}
I'm not sure I fully understand what you want to achieve, but I feel that there are two things that would make your design much simpler:
Don't use Strings for your severity levels. Use enums instead. Enums have a name, may have other fields and methods, and are naturally ordered using their order of definition. And there is no way to make a typo and introduce an unknown severity: they're type-safe
enum Severity {
SEVERE, WARNING, INFO
}
Don't store things in parallel arrays or associate them with maps. Define a class containing the information of your objects:
public class Box {
private String text;
private Severity severity;
}
Now that you have these, you can simply create a List<Box>, and sort it using a Comparator<Box> which sorts them by severity, for example:
List<Box> boxes = Arrays.asList(new Box("Server is on fire", Severity.SEVERE),
new Box("All is good", Severity.INFO),
...);
Collections.sort(boxes, new Comparator<Box>() {
#Override
public int compare(Box b1, Box b2) {
return b1.getSeverity().compareTo(b2.getSeverity());
}
}
or even simpler, with Java 8:
boxes.sort(Comparator.comparing(Box::getSeverity));
You should make your "statuses" (Severe, Info etc) into an Enum.
public enum StatusLevel {
Severe,
Warning,
Info;
}
You can then sort by StatusLevel natively as long as you define the in a top to bottom order.
If you want to supply your Box object directly insead of pulling out the StatusLevel or have a secondary sort by another property like time or alphabetically you should implement your own Comparator
Also you may want to look into SortedMap or other Map that keeps its order so you don't have to resort a HashMap every time as it does not guarantee order.

Best way to save some data and then retrieve it

I have a project where I save some data coming from different channels of a Soap Service, for example:
String_Value Long_timestamp Double_value String_value String_value Int_value
I can have many lines (i.e. 200), with different values, like the one above.
I thought that I could use an ArrayList, however data can have a different structure than the one above, so an ArrayList maybe isn't a good solution in order to retrieve data from it.
For example above I have, after the first two values that are always fixed, 4 values, but in another channel I may have 3, or 5, values. What I want retrieve data, I must know how many values have a particular line, and I think that Arraylist doesn't help me.
What solution could I use?
When you have a need to uniquely identify varying length input, a HashMap usually works quite well. For example, you can have a class:
public class Record
{
private HashMap<String, String> values;
public Record()
{
// create your hashmap.
values = new HashMap<String, String>();
}
public String getData(String key)
{
return values.get(key);
}
public void addData(String key, String value)
{
values.put(key, value);
}
}
With this type of structure, you can save as many different values as you want. What I would do is loop through each value passed from Soap and simply add to the Record, then keep a list of Record objects.
Record rec = new Record();
rec.addData("timestamp", timestamp);
rec.addData("Value", value);
rec.addData("Plans for world domination", dominationPlans);
You could build your classes representing the entities and then build a parser ... If it isn't in a standard format (eg JSON, YAML, ecc...) you have no choice to develop your own parser .
Create a class with fields.
class ClassName{
int numberOfValues;
String dataString;
...
}
Now create an ArrayList of that class like ArrayList<ClassName> and for each record fill that class object with numberOfValues and dataString and add in Arraylist.

Better data structure for faster reads in Map of Map of Map of Lists

I've a scenario where I need to store the map of map of map of list of data hierarchy for processing in memory. And, currently I m thinking to implement the data structure as
Map<Integer, Map<String, Map<Integer, List<String> > > >
and the concretes types are,
HashMap<stdIdInt, HashMap<libraryNameStr, HashMap<topicIdInt, ArrayList<bookNameStr> > > >
As I do not need to maintain any particular order, I m also thinking to replace List with Set (HashSet) which potentially can increase the performance.
Though I've tried till now, I also think using Google' Guava Multimap is a viable alternate, but I m not sure.
Background: I need to store the details of each student's id & their interested book names information categorised by their topic type which will be further organised by library names. I need to process the data & display book names mostly by student id and other times by library name & topic type. And once the book name is shown to the user, I need to delete that entry from the book names list.
The data structure needs to hold & process thousands of entries at high rate and will hold the data for longer time.
Please suggest an approach or another data structure for faster processing, and about the type of the data structure/collection class and their usage combination.
(please note that the scenario I described above is not exact case, but I tried my best to abstract the complexity of the data hierarchy)
I think you are missing a lot of abstractions here. The rule of thumb is: every time a collection holds another collection, intermediate object should be introduced.
In your case this is my suggested OO design:
class Student {
private int id;
private Map<Integer, Library> libraries;
private getLibrary(int id) {return libraries.get(id);}
}
class Library {
private int id;
private Map<Integer, Topic> topics;
private getTopic(int id) {return topics.get(id);}
}
class Topic {
private int id;
private Map<Integer, Book> books;
private getBook(int id) {return books.get(id);}
}
class Book {
private int id;
private String name;
}
And usage:
Map<Integer, Student> students = //...
students.get(6).getLibrary(5).getTopic(4).getBook(3)
Of course this code needs a lot of further improvements. E.g. you shouldn't need more than one . in a line. But it's already much more readable than:
students.get(6).get(5).get(4).get(3)

Categories