Linking two hashmaps via searching or is there a better way? - java

I have a hashmap for orders and another one for orderitems. A method which puts the data into the hashmaps is executed like this:
// THIS ONE ADDS THE ORDERS
// (int orderNumber, String Datum, String salesperson, int customernumber)
mainController.addBestallning(500, "2012/01/01", "Hendrik Gustafsson", 1001);
// THIS ONE ADDS THE ORDERED ITEMS
// (int orderNumber, int linePos, Artikel product, int amount, double price)
mainController.addBestallningsOrderRad(500, 1, mainController.getAllaArtiklar().get(101), 5, 100.00);
Once I find an order by its ordernumber, how do I find the ordereditems?
The only link I have now is the ordernumber, which I save in orderitemshashmap, so I assume some sort of iteration needs to take place, find the matches and return the results.
I tried doing this and got it to work, but only under condition that all of the orderitem positions are also unique.
So, if I was to add another order like this:
mainController.addBestallning(501, "2011/05/02", "Sven Karmageddon", 1002);
mainController.addBestallningsOrderRad(501, 1, mainController.getAllaArtiklar().get(101), 5, 100.00);
I could not find the orderitems for order 501.
Here is what I tried so far. Made a method to find all orders of a customer:
public HashMap<Integer, Bestallning> getAllaKundOrdrar() {
HashMap<Integer, Bestallning> allaKundOrderHashMap = new HashMap<>();
//iterate through all orders
//find the ones which belong to customerid
//place them in allaKundOrderHashMap
//return allaKundOrderHashMap
Iterator iter = tmpBestallningsregister.getAllaBestallningar().keySet().iterator();
while (iter.hasNext()) {
Integer key = (Integer) iter.next();
//String value = (String) controller.getAllaKunder().get(key).getKundNamn();
if ((customerNrToFindOrdersFor) == getAllaBestallningar().get(key).getKundNr()) {
//found an order for this customer, putting it in the hashmap
allaKundOrderHashMap.put(key, getAllaBestallningar().get(key));
}
}
return allaKundOrderHashMap;
}
A method to find all ordereditems from all customers (100% wrong to search like this, I know) and get the ones beloning to a specific order:
//RETURN OF ORDERRADERS HASHMAP FOR SPECIFIC ORDER VIA ORDERREGISTER
public HashMap<Integer, BestallningsOrderRad> getAllaBestallningsBestallningsOrderRader() {
HashMap<Integer, BestallningsOrderRad> allaBestallningsOrderRaderHashMap = new HashMap<>();
//iterate through all orderrader
//find the ones which belong to orderid
//place them in allaKundOrderRaderHashMap
//return allaKundOrderRaderHashMap
Iterator iter = tmpBestallningsregister.getAllaBestallningsOrderRader().keySet().iterator();
while (iter.hasNext()) {
Integer key = (Integer) iter.next();
if ((orderNrToFindOrderRaderFor) == tmpBestallningsregister.getAllaBestallningsOrderRader().get(key).getBestallningsNr()) {
//found an orderrad for this order, putting it in the hashmap
//allaBestallningsOrderRaderHashMap.put(key, getAllaBestallningsOrderRader().get(key));
allaBestallningsOrderRaderHashMap.put(key, getAllaBestallningsOrderRader().get(key));
}
}
return allaBestallningsOrderRaderHashMap;
}
Anyone care to tell me what is it that I am doing wrong?
I've been at this for 20 hours straight...

Don't use two different Map, but only one. What you need is to properly define a Order class that holds all the order data (including suborders, which are sheldom used outside the order) and use just a Map<Integer,Order>
If you insist in having two separate Maps, the second uses the same id but stores a List (it looks like you want it ordered) of suborders.
private Map<Integer, Order> orders;
private Map<Integer, List<SubOrder> suborders;
Stopping a moment before beginning to code and thinking the more appropiate data structures will usually save you a lot of "hell" later.

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.

JAVA : Best performance-wise method to find an object stored in hashMap

I have a bunch of objects stored in hashMap<Long,Person> i need to find the person object with a specific attribute without knowing its ID.
for example the person class:
public person{
long id;
String firstName;
String lastName;
String userName;
String password;
String address;
..
(around 7-10 attributes in total)
}
lets say i want to find the object with username = "mike". Is there any method to find it without actually iterating on the whole hash map like this :
for (Map.Entry<Long,Person> entry : map.entrySet()) {
if(entry.getValue().getUserName().equalsIgnoreCase("mike"));
the answers i found here was pretty old.
If you want speed and are always looking for one specific attribute, your best bet is to create another 'cache' hash-map keyed with that attribute.
The memory taken up will be insignificant for less than a million entries and the hash-map lookup will be much much faster than any other solution.
Alternatively you could put all search attributes into a single map (ie. names, and ids). Prefix the keys with something unique if you're concerned with collisions. Something like:
String ID_PREFIX = "^!^ID^!^";
String USERNAME_PREFIX = "^!^USERNAME^!^";
String FIRSTNAME_PREFIX = "^!^FIRSTNAME^!^";
Map<String,Person> personMap = new HashMap<String,Person>();
//add a person
void addPersonToMap(Person person)
{
personMap.put(ID_PREFIX+person.id, person);
personMap.put(USERNAME_PREFIX+person.username, person);
personMap.put(FIRSTNAME_PREFIX+person.firstname, person);
}
//search person
Person findPersonByID(long id)
{
return personMap.get(ID_PREFIX+id);
}
Person findPersonByUsername(String username)
{
return personMap.get(USERNAME_PREFIX+username);
}
//or a more generic version:
//Person foundPerson = findPersonByAttribute(FIRSTNAME_PREFIX, "mike");
Person findPersonByAttribute(String attr, String attr_value)
{
return personMap.get(attr+attr_value);
}
The above assumes that each attribute is unique amongst all the Persons. This might be true for ID and username, but the question specifies firstname=mike which is unlikely to be unique.
In that case you want to abstract with a list, so it would be more like this:
Map<String,List<Person>> personMap = new HashMap<String,List<Person>>();
//add a person
void addPersonToMap(Person person)
{
insertPersonIntoMap(ID_PREFIX+person.id, person);
insertPersonIntoMap(USERNAME_PREFIX+person.username, person);
insertPersonIntoMap(FIRSTNAME_PREFIX+person.firstname, person);
}
//note that List contains no duplicates, so can be called multiple times for the same person.
void insertPersonIntoMap(String key, Person person)
{
List<Person> personsList = personMap.get(key);
if(personsList==null)
personsList = new ArrayList<Person>();
personsList.add(person);
personMap.put(key,personsList);
}
//we know id is unique, so we can just get the only person in the list
Person findPersonByID(long id)
{
List<Person> personList = personMap.get(ID_PREFIX+id);
if(personList!=null)
return personList.get(0);
return null;
}
//get list of persons with firstname
List<Person> findPersonsByFirstName(String firstname)
{
return personMap.get(FIRSTNAME_PREFIX+firstname);
}
At that point you're really getting into a grab-bag design but still very efficient if you're not expecting millions of entries.
The best performance-wise method I can think of is to have another HashMap, with the key being the attribute you want to search for, and the value being a list of objects.
For your example this would be HashMap<String, List<Person>>, with the key being the username. The downside is that you have to maintain two maps.
Note: I've used a List<Person> as the value because we cannot guarantee that username is unique among all users. The same applies for any other field.
For example, to add a Person to this new map you could do:
Map<String, List<Person>> peopleByUsername = new HashMap<>();
// ...
Person p = ...;
peopleByUsername.computeIfAbsent(
p.getUsername(),
k -> new ArrayList<>())
.add(p);
Then, to return all people whose username is i.e. joesmith:
List<Person> matching = peopleByUsername.get("joesmith");
Getting one or a few entries from a volatile map
If the map you're operating on can change often and you only want to get a few entries then iterating over the map's entries is ok since you'd need space and time to build other structures or sort the data as well.
Getting many entries from a volatile map
If you need to get many entries from that map you might get better performance by either sorting the entries first (e.g. build a list and sort that) and then using binary search. Alternatively you could build an intermediate map that uses the attribute(s) you need to search for as its key.
Note, however, that both approaches at least need time so this only yields better performance when you're looking for many entries.
Getting entries multiple times from a "persistent" map
If your map and its valuies doesn't change (or not that often) you could maintain a map attribute -> person. This would mean some effort for the initial setup and updating the additional map (unless your data doesn't change) as well as some memory overhead but speeds up lookups tremendously later on. This is a worthwhile approach when you'd do very little "writes" compared to how often you do lookups and if you can spare the memory overhead (depends on how big those maps would be and how much memory you have to spare).
Consider one hashmap per alternate key.
This will have "high" setup cost,
but will result in quick retrieval by alternate key.
Setup the hashmap using the Long key value.
Run through the hashmap Person objects and create a second hashmap (HashMap<String, Person>) for which username is the key.
Perhaps, fill both hashmaps at the same time.
In your case,
you will end up with something like HashMap<Long, Person> idKeyedMap and HashMap<String, Person> usernameKeyedMap.
You can also put all the key values in the same map,
if you define the map as Map<Object, Person>.
Then,
when you add the
(id, person) pair,
you need to also add the (username, person) pair.
Caveat, this is not a great technique.
What is the best way to solve the problem?
There are many ways to tackle this as you can see in the answers and comments.
How is the Map is being used (and perhaps how it is created). If the Map is built from a select statement with the long id value from a column from a table we might think we should use HashMap<Long, Person>.
Another way to look at the problem is to consider usernames should also be unique (i.e. no two persons should ever share the same username). So instead create the map as a HashMap<String, Person>. With username as the key and the Person object as the value.
Using the latter:
Map<String, Person> users = new HashMap<>();
users = retrieveUsersFromDatabase(); // perform db select and build map
String username = "mike";
users.get(username).
This will be the fastest way to retrieve the object you want to find in a Map containing Person objects as its values.
You can simply convert Hashmap to List using:
List list = new ArrayList(map.values());
Now, you can iterate through the list object easily. This way you can search Hashmap values on any property of Person class not just limiting to firstname.
Only downside is you will end up creating a list object. But using stream api you can further improve code to convert Hashmap to list and iterate in single operation saving space and improved performance with parallel streams.
Sorting and finding of value object can be done by designing and using an appropriate Comparator class.
Comparator Class : Designing a Comparator with respect to a specific attribute can be done as follows:
class UserComparator implements Comparator<Person>{
#Override
public int compare(Person p1, Person p2) {
return p1.userName.compareTo(p2.userName);
}
}
Usage : Comparator designed above can be used as follows:
HashMap<Long, Person> personMap = new HashMap<Long, Person>();
.
.
.
ArrayList<Person> pAL = new ArrayList<Person>(personMap.values()); //create list of values
Collections.sort(pAL,new UserComparator()); // sort the list using comparator
Person p = new Person(); // create a dummy object
p.userName="mike"; // Only set the username
int i= Collections.binarySearch(pAL,p,new UserComparator()); // search the list using comparator
if(i>=0){
Person p1 = pAL.get(Collections.binarySearch(pAL,p,new UserComparator())); //Obtain object if username is present
}else{
System.out.println("Insertion point: "+ i); // Returns a negative value if username is not present
}

Create lists with java

I am very new in java. I want to create a kind of complex array. I think its called list/collection/map...
My data looks like
-item
ref:GH987
size:22
date:1992
-item
ref:98KJ
size:27
date:2000
-item
ref:ZXJ212
size:24
date:1999
I do not prefer to create an item Class and store the 3 instance in an array.
I found something called Map but it really confused me and I don't understand how could I access the values after creating the data. Could you help me how to start with this ?
final Map<String, List<String>> data = new LinkedHashMap<String, List<String>>();
data.put("item", new LinkedList<String>());
You have to create an Item class, that's the whole point of OOP!
Very minimal example:
public class Item {
public String ref;
public int size;
public int date;
public Item(String ref, int size, int date) {
this.ref = ref;
this.size = size;
this.date = date;
}
}
Then it's just a List<Item> and you can access each part with myList.get(i).ref etc:
List<Item> l = new ArrayList<>();
l.add(new Item("GH987", 22, 1992));
l.add(new Item("98KJ", 27, 2000));
...
for (Item it : l)
System.out.println("Ref: "+item.ref+", size: "+item.size+", date: "+item.date);
Now, if you really want to use a Map to store each attribute, you have to think what would be your unique key. Let's suppose it's ref, which is a String:
Map<String,Integer> sizes = new LinkedHashMap<>(); // LinkedHashMap keeps the insert order
Map<String,Integer> dates = new LinkedHashMap<>();
sizes.put("GH987", 22);
dates.put("GH987", 1992);
sizes.put("98KJ", 27);
dates.put("98KJ", 2000);
then it's difficult to access all members as they're not bundled in a single instance:
String ref = "GH987";
System.out.println("Ref: "+ref+", size: "+sizes.get(ref)+", date: "+dates.get(ref))
Here you should realize that if a Map hasn't been updated, it will return null on the value and you'll have to handle consistency yourself. It is also a pain to create so many objects just to store single attributes, which in your case are Number subclasses (e.g. Integer) instead of native types, which are far more efficient.
So do yourself a favor, and create your Item class. Then you can use a Map to quickly access a particular item based on its key, which looks like the ref member:
myMap.put(ref, new Item(ref, size, date));
Item it = myMap.get(ref);
...
Yes you can choose Map with a class and having it's reference as a key for ex
Map<String,Item> map = new HashMap<>();
Assuming reference is unique. You can store values like
map.put(item.getReference(),item);

Get key from HashMap in Android by position or index

I have:
public static HashMap<String, String> CHILD_NAME_DOB = new HashMap<>();
Suppose the values in CHILD_NAME_DOB are:
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
I am trying to fetch the last key element from CHILD_NAME_DOB. That is, I want to fetch key alisha from the example above to temporary String name.
Also I want to know on how to fetch data by index.
Eg.: if int index = 2 , I want key "Neha" in String name
TIA.
Edit: DateOfBirth value (value data in CHILD_NAME_DOB) is dynamic and is unknown. So THIS LINK is not what I want.
Single line solution:
First note that the Java HashMap does not guarantee the order of entries. So each time you iterate over a HashMap, entries appear in different positions. You will need LinkedHashMap that guarantees the predictable iteration order.
Map<String, String> CHILD_NAME_DOB = new LinkedHashMap<>();
Get the key by index:
key = (new ArrayList<>(CHILD_NAME_DOB.keySet())).get(index)
Get the value by index:
CHILD_NAME_DOB.get(key)
Thanks to #Pentium10 for this answer.
And I little modified it according to my need.
String key="default";
Iterator myVeryOwnIterator = CHILD_NAME_DOB.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
key=(String)myVeryOwnIterator.next();
//String value=(String)meMap.get(key);
}
Toast.makeText(viewEnterChildExp.getContext(), "Key: "+key , Toast.LENGTH_LONG).show();
I'm getting the last key element by this.
I'll update as soon I also get to find an easy way to key by index.
This way to get key....
public static String getHashMapKeyFromIndex(HashMap hashMap, int index){
String key = null;
HashMap <String,Object> hs = hashMap;
int pos=0;
for(Map.Entry<String, Object> entry : hs.entrySet())
{
if(index==pos){
key=entry.getKey();
}
pos++;
}
return key;
}
You can also use an ArrayMap instead of a HashMap. To get the value by index use:
ArrayMap.valueAt(index);
To get the Key at an index use:
ArrayMap.keyAt(index);
Fetching the "last" key and fetch by index is not supported by HashMap. You can use a LinkedHashMap and lookup the element with index 2 (or the last element) by iterating over it. But this will be a O(n) operation.
I suggest you use a List<Pair<String, String>> if the order of the keys/values is important to you and you wish to do index based lookup.
If both key based and index based lookup is important to you, you could use a combined data structure that consists of both a List and a HashMap, but note that removal of elements will be O(n).
You can create a class Child
public class Child(){
private String name;
private String number;
....
}
and then put this object in a List
public static List<Child> CHILD_NAME_DOB = new ArrayList<Child>(); // using LinkedList would defeat the purpose
in this way you can invoke the method get(int index), that returns the element at the specified position in this list.
In your example
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
invoking CHILD_NAME_DOB.get(2) you'll get <neha,05091992>(as Child object)
HashMap does not have a concept of ordering, so getting the n-th entry does not make sense. You could use a TreeMap instead, which is ordered on its keys.
However, you should reconsider your model as you seem to have conflicting interests. On the one hand, accessing by index is typical for Lists, whereas accessing by key is typical for Maps. I'm not sure in which situation you'd want to do both.
If you really want to do both index and key accessing, you could write your own data structure that stores the data in a list combined with a mapping from key to index and vice versa. I would recommend against this, but if that's really what you want, then I think that's the best solution.
I know it is not the best solution, but what about this solution (pseudocode!). Just combine List and Map in one class.
public class UserBirthday {
private List<String> names = new ArrayList<>();
private Map<String, String> CHILD_NAME_DOB = new HashMap<String, String>();
public void add(String name, String bd) {
if (!CHILD_NAME_DOB.containsKey(name)) {
names.add(name);
}
CHILD_NAME_DOB.put(name, bd);
}
public String getByName(String name) {
return CHILD_NAME_DOB.get(name);
}
public String getByIndex(int index) {
return getByName(names.get(index)); // TODO: range test
}
public static void main(String[] args) {
UserBirthday ub = new UserBirthday();
ub.add("dit", "12345678");
ub.add("lea", "234239423");
ub.add("alex", "43534534");
ub.add("ted", "099098790");
System.out.println(ub.getByIndex(2));
System.out.println(ub.getByName("alex"));
}
}
You may get some problems if you remove an entry, but it should be just a suggestion.
for (String key : hmList.keySet()) {
String value = hmList.get(key);
Log.e("HashMap values", "key=" + key + " ,value=" + value);
}

How to Iterate Two Lists and compare the items within?

I'm almost at the end of my final project in the university, I'm trying to control my inStock with my current Stock of articles.
My stock contains the following attributes:
int idMercaderia;
int cantidad;
int idSucursal;
I have two lists that contains Inventario type POJOs:
List <Inventario> stock = new InventarioDAO().findAll();
List <Inventario> inStock = new ArrayList <Inventario>();
Before persist in the database, I want to compare the attribute idMercaderia in both of 'em, if they're the same don't create another entry and just add the quantity cantidad to the current stock and do a saveOrUpdate() if not just create another entry.
I'm really stuck in this part and currently run out of ideas after trying iterate both Lists but I can't figure out the stock thingy.
Any help/code will be really appreciated.
you need to implement an equals() method if not already happened in the Inventario to compare idMercaderia in there. then
for(Inventario item: stock){
if(inStock.contains(item)){
item.cantidad++;
}
}
Create a Map<Integer, Inventario> of your first list to map an idMercaderia to one Inventario. Then iterate your second list and check for each item the corresponding one in the map.
Map<Integer, Inventario> map = new HashMap<Integer, Inventario>();
for (Inventario item : stock) {
map.put(item.getIdMercaderia(), item);
}
and
for (Inventario item : inStock) {
int idMercaderia = map.getIdMercaderia();
Inventario inventario = map.get(idMercaderia);
if (inventario == null) {
// error handling
continue;
}
if (item.getCantidad() == inventario.getCantidad() {
// handle
}
}

Categories