Nested RepeatingGrps within Java Design Issue - java

EDIT: I have two Objects I must map one to the other. The problem is that the attributes don't exactly match up. The object coming in I am mapping from is flat has a bunch of getters and setters. All very nice and easy to work with.
I have to map this to a an Object which has somewhat of a different structure, within Groups such as SecAltIDGrp[] and attritubes such as those below. Which is set using
ObjectToMapTo.setSecAltIDGrp(SecAltIDGrp[])
I have a few repeating groups which I must map with values from a getter from the flat object the problem is this. The object to be mapped to has Array[]s of Grps which must be populated by various different getters from the flat object. I cannot think of a clean way to do this.
For instance, I have a code an array of comments which has the following structure.
public SecAltIDGrp[] populateComments(int NoComments)
{
SecAltIDGrp[] x = new SecAltIDGrp[NoComments];
for(int i; i < NoComments; i++)
{
x[i].setAltID(obj.getVal);
x[i].setAltIDSource(arg0, arg1);
}
}
however each element of the array the is populated by a different getter from the flat object...
I cannot thing a nice of doing this bar inserting a if statement within the array and passing in the object as a parameter. This is rather horrific coding.
I am supposed to do this for a number of such groups. With some of the array element setters requiring arrays themselves.

Instead of using Array, try using HashMaps, which will help you pass/store the objects more easily.
If you are not really interested with the hashmap keys, then you can simply use ArrayList.
The HashMap will store the require group, along with the key. The key here will be similar to the array Index, you were planning to use.
public HashMap< Integer , SecAltIDGrp > populateComments( int NoComments )
{
HashMap< Integer , SecAltIDGrp > hmSec = new HashMap< Integer , SecAltIDGrp >();
for(int i; i < NoComments; i++)
{
SecAltIDGrp x = new SecAltIDGrp();
x.setAltID(obj.getVal);
x.setAltIDSource(arg0, arg1);
hmSec.put( i , x );
}
return hmSec;
}
public class SecAltIDGrp{
String altId = "";
String altIdSource = "";
public void setAltIDSource( String altIDSource )
{
this.altIdSource = altIDSource;
}
public void setAltID( String altId )
{
this.altId = altID;
}
}
Make sure the getters and setters will also have the appropriate parameters to satisfy the generics to prevent any warnings during compilation.
public class ObjectToMapTo
{
private HashMap< Integer , SecAltIDGrp > hmPrivGrp = new HashMap< Integer,SecAltIDGrp >();
public void setSecAltIDGrp( HashMap< Integer , SecAltIDGrp > hmSecAltIDGrp)
{
this.hmPrivGrp = hmSecAltIDGrp;
}
}
this is how you set the particular group. store the hashmap instead of an array.
ObjectToMapTo.setSecAltIDGrp( hmSec );
You will be able to iterate through the hashmap and be able to retrieve individual SecAltIDGrp
Some stuff to read up:
http://www.javadeveloper.co.in/java-example/java-hashmap-example.html

Related

Is there a Map object with takes index and key and object? Java

I'm trying to emulate a rotor of an enigma machine in Java.
I need an object which takes an index, a key and an object, because I unsuccessfully tried HashMaps like this:
private HashMap<Integer,Integer> rotorWiring = new HashMap<Integer, Integer();
private HashMap<Integer,Integer> reverseRotorWiring = new HashMap<Integer, Integer>();
//The "wiring" of the rotor is set from a String,
public void setRotorWiring(String Wiring) {
if (Wiring.length()==26) {
for (int i=0; i<Wiring.length();i++ ) {
char tempChar = Wiring.charAt(i);
int valueOfChar = (int)tempChar-64;
if (valueOfChar<=26){
this.rotorWiring.put(i+1,valueOfChar);
this.reverseRotorWiring.put(valueOfChar,i+1);
}
}
}
}
So far so good, this allows me to translate e.x. an A to an E, however, once I tried to simulate a turn of the rotor like this:
//It should be mentioned that I designing the program to only accept characters a to z inclusive.
public void turn() {
for (int i=1;i<=rotorWiring.size();i++) {
if (i!=26) {
rotorWiring.replace(i, rotorWiring.get(i+1));
}
else {
rotorWiring.replace(i, rotorWiring.get(1));
}
}
for (int i=1;i<=rotorWiring.size();i++) {
if (i!=26) {
reverseRotorWiring.replace(i, rotorWiring.get(i+1));
}
}
}
However, I noticed that this rather simulates an offset of the internal wiring of the rotor rather than a turn... I'm asking for a "Map"-like solutions with an index, key and object, because that would allow me to offset the index of all the keys and objects by 1, thus simulating a turn.
I am, however, open to suggestions for different solutions to this problem.
It should be mentioned that I'm a bit of a novice, and therefore appreciate rather in-depth explanations.
Many thanks.
Welcome to StackOverflow. There doesn't exist an implementation of what you have described in JDK. However, there are more ways to achieve the storing of Integer-String-Object. Note that both the index and the key are unique by definition. Also, note that the index-key are tightly coupled. You might want to put a Map to another Map:
Map<Integer, Map<String, MyObject>> map;
Or use a collection characteristic for indices:
List<Map<String, MyObject>>
Be careful with removing items which change the index of all the subsequent elements - replace it with null instead to keep the indices. Alternatively, you can create a decorator for your defined object with index/key:
Map<Integer, MyDecoratedObject> map;
Where the MyDecoratedObject would look like:
public class MyDecoratedObject {
private final String key; // or int index
private final MyObject delegate;
// Full-args constructor, getters
}
Finally, it's up to you to pick a way that satisfied your requirements the most.
A map of maps was the solution! It was solved like this:
private HashMap<Integer,HashMap<Integer,Integer>> rotorWiring = new HashMap<Integer, HashMap<Integer,Integer>>();
private HashMap<Integer,HashMap<Integer,Integer>> reverseRotorWiring = new HashMap<Integer, HashMap<Integer,Integer>>();
public void setRotorWiring(String Wiring) {
if (Wiring.length()==26) {
for (int i=0; i<Wiring.length();i++ ) {
HashMap<Integer, Integer> wire = new HashMap<Integer, Integer>();
HashMap<Integer, Integer> reverseWire = new HashMap<Integer, Integer>();
char tempChar = Wiring.charAt(i);
int valueOfChar = (int)tempChar-64;
if (valueOfChar<=26){
wire.put(i+1,valueOfChar);
reverseWire.put(valueOfChar,i+1);
rotorWiring.put(i, wire);
reverseRotorWiring.put(i, reverseWire);
}
}
}
}

Iterate over a HashMap with multiple values per key

I am currently learning sets and maps through university (still using Java 7).
They have given us a half finished to-do list app to complete. Currently the to-do list takes three String local variables to allow the user to state a job (aJob), a time to do it (aTime) and a date to do it (aDate).
The app also has an instance variable (today) that holds todays date.
I need to come up with a way to check the HashMap for any tasks that are due today. So I need to be able to query just the HashMap values attributed by the aDate local variable.
I know that to iterate Maps that I can place the keys or the values into a Set and then iterate over the set - not a problem. But if I use the values() method (within the Map class) to put these into a set - it places all three Strings per key into the set. I just want to move the aDate values into a set.
Any ideas?
I only seem to be able to find examples where the Maps have just a single Key and Single Value. This list has a single key and three values per key.
Any pointers would be good?
Kind Regards
Edit.....
Just thought I would add some code to help as there have been several different approaches - which I am all very greatful for. But not sure if they suit my needs....
The Job Class is constructed as such...
public Job(String aJob, String aDate, String aTime)
{
Job = aJob;
date = aDate;
time = aTime;
}
I then create the map within the instance declarations for the To Do List class....
Map<Integer, Job> toDoList = new HashMap<>();
So I need to know the best way to iterate over this map, but it is only the Job attribute 'aDate' that is possibly going to hold the value I am after.
Not sure if that helps at all?
Kind Regards
If really the only structure you're allowed to use is a Map where each key has 3 values (which is the case if I understand correctly), of which only one is a Date, you technically could do the following:
map.values()
.stream()
.filter(Date.class::isInstance)
...whatever else you want to do
The other suggested solutions are far better though, design wise.
If you can't use a custom class, as suggested by Toisen, maybe HashMap<String, HashMap<String, ArrayList<String>>> could do the trick for you.
I've added a sample of how to use it (as well as populating it with some random data)
public class FunkyMap {
private HashMap<String, HashMap<String, ArrayList<String>>> jobs;
// For random data
private String[] job = {"EAT", "SLEEP", "FART", "RELAX", "WORK"};
private String[] time = {"MORNING", "BEFORENOON", "NOON", "AFTERNOON", "EVENING", "MIDNIGHT"};
private String[] date = {"FIRST", "SECOND", "THIRD", "FOURTH"};
public FunkyMap() {
jobs = new HashMap<>();
// To populate some random data
Random r = new Random();
for(int i = 0; i < 20; i++) {
String d = date[r.nextInt(date.length)];
if(jobs.containsKey(d)) {
HashMap<String, ArrayList<String>> inner = jobs.get(d);
String t = time[r.nextInt(time.length)];
if(inner.containsKey(t)) {
inner.get(t).add(job[r.nextInt(job.length)]);
} else {
List<String> s = Arrays.asList(new String(job[r.nextInt(job.length)]));
inner.put(t, new ArrayList<String>(s));
}
} else {
jobs.put(d, new HashMap<String, ArrayList<String>>());
}
}
// Actual iteration over date => time => jobs
Iterator<String> i = jobs.keySet().iterator();
while(i.hasNext()) {
String iKey = i.next();
HashMap<String, ArrayList<String>> inner = jobs.get(iKey);
System.out.println("Jobs scheduled for " + iKey);
Iterator<String> j = inner.keySet().iterator();
while(j.hasNext()) {
String jKey = j.next();
ArrayList<String> actualJobs = inner.get(jKey);
System.out.println("\tAt " + jKey);
for(String s : actualJobs) {
System.out.println("\t\tDo " + s);
}
}
}
}
public static void main(String[] args) {
new FunkyMap();
}
}
I took the liberty to assume that dates were unique, and time was unique per date, while a time could hold any number of jobs including duplicates. If the last assumption with jobs is not true, you could swap ArrayList<String> with Set<String>.
Just create a class that holds all data that you need. E.g.
If you need something strange like Map<String, Tuple<String, Integer, Date>> just make a new class that holds the Tuple:
class TupleHolder {
private String firstValue;
private Integer secondValue;
private Date thirdValue;
// get/set here...
}
and use it: Map<String, TupleHolder>

`ArrayList of HashMap` or `LinkedHashMap` to get item by index

My need to store a a huge amount of data in the key-value form.
Also, I have two requirements
query data via the index, like from an array.
hence the order in the data structure must be preserved.
For Requirement 2 - I can use a LinkedHashMap.
For Requirement 1 - I have two options :
1.1 | To implement an ArrayList Of HashMap. [ArrayList<HashMap<String,String>>]
1.2 | To implement a LinkedHashMap and query the items by index using something like
-> new ArrayList(hashMapObject.entrySet()).get(0);
The Question is which is better among 1.1 or 1.2 ?
By better, I mean - efficient in terms of memory and space.
Let's assume the volume of data is in the order of 50 to 100 key-value pairs with average sized Strings - say every key is 10-30 characters and value is 30-50 characters.
Try using SortedMap.
For example:
SortedMap<Key, Value> map = new TreeMap<Key, Value>();
This way you get the fast lookup time (via key), but they also remain ordered.
You can then iterate over the data like so:
for(Key k : map.keySet()) {
process(map.get(k));
}
I used them recently to analyze 10s millions tweets where the key was a date, and the value was a counter. I wanted to maintain the ordering of the dates.
update If you can get by with just itereating over the data, then my method will suffice. Perhaps you could supply a small example? If it's absolutely required that you can reference the data by index as well, it seems like you would just want to maintain two datastructures like #Jim mentioned. I'ved had to do that before.
Remember that collections do not contain the objects, only references to objects.
Use two collections:
An ArrayList to store the references for access by index
A HashMap to store the references for access by key
For example:
List<MyValue> list = new ArrayList<MyValue>(100000);
Map<MyKey,MyValue> map = new HashMap<MyKey,MyValue>(100000);
while(moreItems) {
// read input
MyKey key = ...
MyValue value = ...
list.add(value);
map.put(key,value);
}
// lookup by index
MyValue v1 = list.get(11241);
// lookup by key
MyValue v2 = map.get(someKey);
If you need to cross-reference (i.e. given a value object, find its index or its key) you have some options:
Save the index and key in the the value object itself
Wrap the value in a "handle" that contains the key and index.
For example
class Wrapper {
MyKey key;
MyValue value;
int index;
// constructor, getters and setters
}
int index=0;
while(moreItems) {
// read input
MyKey key = ...
MyValue value = ...
Wrapper w = new Wrapper(key,value,index++);
list.add(w);
map.put(key,w);
}
...
Wrapper w = list.get(23410);
MyKey k = w.getKey();
MyValue v = w.getValue();
int i = w.getIndex();
...
I think the LinkedHashMap is the best solution, but to get the item, you can use
hashMapObject.values().toArray()[index]
However, the toArray method will be slow for large amounts of data. But that is something you'll have to test.
If speed is really an issue, you can maintain a HashMap and an ArrayList.
I went with experimentating it myself. Turns out the method of creating an ArrayList of HashMaps is about 40 times faster with 1000 elements.
public class HashMapVsArrayOfHashMap {
public static void main(String[] args){
ArrayList<HashMap<String, String>> listOfMaps=new ArrayList<HashMap<String,String>>();
for( int i=0;i<1000;i++){
final int finalI=i;
listOfMaps.add(new HashMap<String, String>(){{put("asdfasdfasdfasdfadsf"+finalI,"asdfsdafasdfsadfasdf"+finalI);}});
}
LinkedHashMap<String, String> map=new LinkedHashMap<String, String>();
for(int i=0;i<1000;i++)
map.put("asdfasdfasdfasdfadsf"+i,"asdfsdafasdfsadfasdf"+i);
int position=700;
testArrayList("Method1:ArrayListOfHashMaps",position,listOfMaps);
testHashMap("Method2:LinkedHashMap",position,map);
}
private static void testArrayList(String string, int position,
ArrayList<HashMap<String, String>> listOfMaps) {
long start, end;
start=System.nanoTime();
listOfMaps.get(position).get("asdfasdfasdfasdfadsf"+position);
end=System.nanoTime();
System.out.println(string+"|Difference = "+(end-start));
}
private static void testHashMap(String string, int position,
LinkedHashMap<String, String> map) {
long start, end;
start=System.nanoTime();
String s= new ArrayList<String>(map.keySet()).get(position);
end=System.nanoTime();
System.out.println(string+"|Difference = "+(end-start));
}
}
When you increase the size to 30,000 elements - the difference is HUGE.

Multiple values in one ArrayList key

I'm trying to put multiple values in one arraylist key, but instead I get an error:
Class:
public class BestellenWindow extends javax.swing.JFrame {
private ArrayList<String> bestelling = new ArrayList<String>();
public BestellenWindow() {
initComponents();
}
Action performed:
private void BestellenbuttonActionPerformed(java.awt.event.ActionEvent evt)
{
bestelling.add(Barcodetext.getText(), Aantaltext.getText());
System.out.println(bestelling.get(0));
}
error:
no suitable method found for add(java.lang.String,java.lang.String)
method java.util.ArrayList.add(int,java.lang.String) is not applicable
(actual argument java.lang.String cannot be converted to int by method invocation conversion)
method java.util.ArrayList.add(java.lang.String) is not applicable
An ArrayList is just a list. It doesn't have a "key". If you want to store objects by key, use an implementation of interface Map (for example HashMap) instead of a List.
But, a normal Map can store only one value per key. If you want to store multiple values, you can use a Map<K, List<V>> (where K is the key type and V the value type), or you could use for example Multimap from Google Guava.
But there's also another, perhaps better solution. Create a new class to hold the barcode and aantal, and store instances of that class in your ArrayList. For example:
public class Bestelling {
private String barcode;
private int aantal;
public Bestelling(String barcode, int aantal) {
this.barcode = barcode;
this.aantal = aantal;
}
public String getBarcode() {
return barcode;
}
public int getAantal() {
return aantal;
}
}
// Later:
Bestelling b = new Bestelling(Barcodetext.getText(),
Integer.parseInt(Aantaltext.getText()));
bestelling.add(b);
In Java there are two elements.
1. List Interface : This does not hold any key. It has the collection of the values. You can add one by one by add(value) method.
2. Map : This holds one key for a set of value.
List<String> userName = new ArrayList<String>();
userName.add("Jesper");
userName.add("Mafue");
Map<Long,String> userMap = new HashMap<Long,String>();
userMap.put(1l,"Jesper");
userMap.put(2l,"Mafue");
From map you can retrieve the values by providing key.
You are trying to invoke the method
list.add(int index, String value)
that it is used to insert an element at a specific position.
If this is what you actually want to do then I guess that Barcodetext should contain a string that is a number, so you need to convert it to an int with
Integer.parseInt(Barcodetext.getText())
If instead you want to add multiple values just call the method twice:
bestelling.add(Barcodetext.getText());
bestelling.add(Aantaltext.getText());
Use either:
bestelling.add(...);
bestelling.add(...);
...
or
bestelling.addAll(Arrays.asList(..., ...));

String Array Into HashMap Collection Object

I have the following
String[] temp;
which returns
red
blue
green
I would like to add the string array into a collection obejct like HashMap so that I could retrieve values in any class like
HashMap hash = New HashMap();
hash.get("red");
hash.get("blue");
hash.get("green");
How can I do this?
Thanks
Update 1
String str = "red,blue,green";
String[] temp;
String delimiter = ",";
temp = str.split(delimiter);
for (int i = 0; i < temp.length; i++) {
System.out.println(temp[i]);
}
With the above code, I would like to retrieve values based on values in array. E.g. I would like to get the values in from another class by calling hash.get("One"), which would return red, hash.get("Two") which would return blue and so forth.
Map<String, String> hash = new HashMap<String, String>();
for(i = 0 ; i < temp.length(); i++)
{
hash.put(temp[i], temp[i]);
}
Then you can retrieve from map
hash.get (temp[i]);
HashMap<String, String>() map = new HashMap<String, String>();
map.put(temp[i], temp[i]);//here i have considered key as the value itself.. u can use something else //also.
My doubt how I do map temp[i] with red, blue or green?
Using a hash map won't solve this problem directly. Currently you need to write
temp[ someNumberHere ];
so
temp[ 1 ];
yields a String "blue"
If you have a hashMap then instead you might write
myColourMap.get( someNumberHere );
so
myColourMap.get( 1 );
Would yield "blue". In either case you are converting a value to a corresponding string, but you do need to know that "someNumber". If you want "blue" you need to know to ask for number 1.
It may be that what you need is to use nicely named constant values:
public Class Colours {
public static final int RED = 0;
public static final int BLUE = 1;
public static final int GREEN = 1;
// plus either the array of strings or the hashMap
public statuc String getColour(int colourNumber ) {
return myArray[colourNumber]; // or myMap.get(colourNumber)
}
}
Your clients can now write code such as
Colours.getColour( Colour.RED );
[It is better to use enums than just raw ints, but let's not divert from arrays and hashMaps right now].
Now when might you prefer a hashMap instead of an array? Consider that you might have more colours, for example 12695295 might be "light pink" and 16443110 might be "lavender".
Now you really don't want an array with 16,443,110 entries when you are only using perhaps 500 of them. Now a HashMap is a really useful thing
myMap.put( Colour.LAVENDER, 16443110 );
and so on.

Categories