Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm implementing a bag of Integers in java and I'm not sure how to do so. I would like to do so with either a HashMap, LinkedHashMap, TreeMap, TreeSet, or HashSet. Some of the things I'd like to do are
Be able to count the number of occurrences of a certain element (So I cannot use a set)
be able to add without the structure immediately deleting duplicate integers
I've tried implementing a map so far but I run into problems when I try to add to the map because I'm trying to implement a bag of integer objects not key value pairs.
public class Bag<Integer> {
private int count = 0;
private HashMap <T, Integer> map;
//class constructor
public Bag(){
this.map = new HashMap <T, Integer>();
}
would a linked hash set be best? I'd like to add duplicate Integers.
If I read your question correctly, you simply want
Map<Integer, Integer> integerBag = new HashMap<>();
Key: represents the different Integers you have in your bag.
Value: represents the count how often the corresponding key was added.
When adding a "new" Integer, you put(newValue, 1) into the map. When the same number comes in, you increase that counter; and decrease on removal.
Beyond that:
without the structure immediately deleting duplicate integers doesn't make much sense. Integers are just numbers; why would you want to remember "6 6 6" ... when you could remember "I got 6 three times" instead?!
Given your comments:
you don't need to change the signature of your method. The compiler generates code to turn primitive types such as int into their big brothers such as Integer automatically. That is called auto-boxing.
but you can also do that manually.
See here:
int intval =5;
Integer asInteger = Integer.valueOf(intval);
if (Integer bag.contains(asInteger)) {
Just use a HashMap. You might want to count how many duplicates you have:
Map<Whatever, Long> bag = new HashMap<>();
To add an element, use the merge method:
bag.merge(someElement, 1, (oldValue, value) -> oldValue + 1);
And to remove an element, you might want to use the computeIfPresent method:
bag.computeIfPresent(someElement, (key, value) -> (value == 1 ? null : value - 1));
Because of your requirement #2, I don't think you can use any collection based on hashing. If you need to retain duplicate Integers, you'll need to use a List.
Adding a new items is easy, just call add() on the list. Finding all items requires a short loop; to count them just call size() on the resulting list.
The code below is not tested.
public class Bag<T> {
private List<T> items = new ArrayList<>();
public void add( T i ) { items.add(i); }
public List<T> findAll( T target ) {
ArrayList<T> retVal = new ArrayList<>();
for( T i : items ) {
if( i.equals(target) )
retVal.add( i );
}
return retVal;
}
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am working on a personal project on Java. I have a Map called allow and the second parameter is another Map. I am trying to compare the second parameter of the Map inside allow. If anyone can help me that would be a big help.
public boolean checkBank(String bank, int cNumber){
Map <String, Map<String, String> > allow = new HashMap<>();
String num = Integer.toString(cNumber);
Iterator<Map.Entry<String, Map<String, String>>> entries = allow.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, Map<String, String>> entry = entries.next();
if (entry.getKey().equals(bank)) {
String all = entry .getValue().get(0);
for (int i = 0; i < entry.getValue().size(); i++) {
if(entry.getValue().equals(num)) {
return true;
}
}
}
}
return false;
}
On the statement: if(entry.getValue().equals(num))
entry.getValue() is a Map, but num is a string. These two are not compatible types, so they can never be equal.
It's worth noting that you are looking for the one entry with the key value equal to bank. Rather than scan through all Map.Entry objects for the one which has the right value, why not just use the statement:
Map<String,String> map = allow.get(bank);
Let the outer map do this work for you.
Your question didn't exactly make clear what you wanted, but I'm guessing that you either want to look, in the inner Map, for an Entry where either the key or the value matches num. You can do that with either
map.containsKey(num)
or
map.containsValue(num)
Is that basically what you are looking for?
I am currently working towards on an implementation that basically involves attending to an arraylist of objects, say a 1000, find commonalities in their properties and group them.
For example
ArrayList itemList<CustomJaxbObj> = {Obj1,obj2,....objn} //n can reach to 1000
Object attributes - year of registration, location, amount
Grouping criteria - for objects with same year of reg and location...add the amount
If there are 10 Objects, out of which 8 objects have same loc and year of registration, add amount for all 8 and other 2 whose year of reg and loc match. So at the end of operation I am left with 2 objects. 1 which is a total sum of 8 matched objects and 1 which is a total of 2 matched criteria of objects.
Currently I am using dual traditional loops. Advanced loops are better but they dont offer much control over indices, which I need to perform grouping. It allows me to keep track of which individual entries combined to form a new entry of grouped entries.
for (i = 0; i < objlist.size(); i++) {
for(j = i+1; j< objList.size();j++){
//PErform the check with if/else condition and traverse the whole list
}
}
Although this does the job, looked very inefficient and process heavy. Is there a better way to do this. I have seen other answers which asked me to use Java8 streams, but the operations are complex, hence grouping needs to be done. I have given an example of doing something when there is a match but there is more to it than just adding.
Is there a better approach to this? A better data structure to hold data of this kind which makes searching and grouping easier?
Adding more perspective, apologies for not furnishing this info before.
The arraylist is a collection of jaxb objects from an incoming payload xml.
XML heirarchy
<Item>
<Item1>
<Item-Loc/>
<ItemID>
<Item-YearofReg/>
<Item-Details>
<ItemID/>
<Item-RefurbishMentDate>
<ItemRefurbLoc/>
</Item-Details>
</Item1>
<Item2></Item2>
<Item3></Item3>
....
</Item>
So the Jaxb Object of Item has a list of 900-1000 Items. Each item might have a sub section of ItemDetails which has a refurbishment date.The problem I face is, dual loops work fine when there is no Item Details section, and every item can be traversed and checked. Requirement says if the item has been refurbished, then we overlook its year of reg and instead consider year of refurbishment to match the criteria.
Another point is, Item Details need not belong to same Item in the section, that is Item1's item details can come up in Item2 Item Details section, item id is the field using which we map the correct item to its item details.
This would mean I cannot start making changes unless I have read through the complete list. Something a normal for loop would do it, but it would increase the cyclomatic complexity, which has already increased because of dual loops.
Hence the question, which would need a data structure to first store and analyse the list of objects before performing the grouping.
Apologies for not mentioning this before. My first question in stackoverflow, hence the inexperience.
Not 100% sure what your end goal is but here is something to get you started. to group by the two properties, you can do something like:
Map<String, Map<Integer, List<MyObjectType>>> map = itemList.stream()
.collect(Collectors.groupingBy(MyObjectType::getLoc,
Collectors.groupingBy(MyObjectType::getYear)));
The solution above assumes getLoc is a type String and getYear is a type Integer, you can then perform further stream operations to get the sum you want.
You can use hash to add the amounts of elements having same year of registration and location
You can use Collectors.groupingBy(classifier, downstream) with Collectors.summingInt as the downstream collector. You didn't post the class of the objects so I took the leave to define my own. But the idea is similar. I also used AbstractMap.SimpleEntry as the key to the final map.
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupByYearAndLoc {
static class Node {
private Integer year;
private String loc;
private int value;
Node(final Integer year, final String loc, final int value) {
this.year = year;
this.loc = loc;
this.value = value;
}
}
public static void main(String[] args) {
List<Node> nodes = new ArrayList<>();
nodes.add(new Node(2017, "A", 10));
nodes.add(new Node(2017, "A", 12));
nodes.add(new Node(2017, "B", 13));
nodes.add(new Node(2016, "A", 10));
Map<AbstractMap.SimpleEntry<Integer, String>, Integer> sums = nodes.stream()
// group by year and location, then sum the value.
.collect(Collectors.groupingBy(n-> new AbstractMap.SimpleEntry<>(n.year, n.loc), Collectors.summingInt(x->x.value)));
sums.forEach((k, v)->{
System.out.printf("(%d, %s) = %d\n", k.getKey(), k.getValue(), v);
});
}
}
And the output:
(2017, A) = 22
(2016, A) = 10
(2017, B) = 13
I would make "Year+Location" concatenated be the key in a hashmap, and then let that map hold whatever is associated with each unique key. Then you can just have one "for loop" (not nested looping). That's the simplest approach.
This question already has answers here:
HashMap with multiple values under the same key
(21 answers)
Closed 6 years ago.
I have 100 entries and I have to have to hash these into a hashtable of a limited size.
I know how to work with the first entry, ht.put(k,v) does the trick.
But as soon as I want to add another value to it, the old one gets overwritten. I don't want to do that, I want to append it in a linkedlist or arraylist.
Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>(211);
ht.put(1, 40);
ht.put (1, 60);
System.out.println(ht.get(1));
// output is 60
How to make it both 40 and 60?
You can have List as value type like:
Hashtable<Integer,List<Integer>> ht = new Hashtable<Integer,List<Integer>>(211);
And your put operation would look like:
public static void put(Hashtable<Integer,List<Integer>> ht, int key, int value) {
List<Integer> list = ht.get(key);
if (list == null) {
list = new ArrayList<Integer>();
ht.put(key, list);
}
list.add(value);
}
[UPDATE1]
If you want you can make your one extension of Hashtable like:
public class MyHashtable extends Hashtable<Integer,List<Integer>> {
public MyHashtable(...) { // add params if needed
super(...);
}
// with additional method:
public static void putOne(int key, int value) {
List<Integer> list = this.get(key);
if (list == null) {
list = new ArrayList<Integer>();
this.put(key, list);
}
list.add(value);
}
}
You need linear probing http://www.sanfoundry.com/java-program-implement-hash-tables-linear-probing/
It's not possible to store more than one value in a cell of a hash table
When trying to map a new key to an already occupied cell this is called a collision.
There are a few algorithm schemes to try and work around collision, one is Linear probing - which finds the next most appropriate free space for the key to be stored
The data structure you are looking for is called Multi Map. By definition it has different interface than a map, because it allows multiple values associated with the same key.
There's no standard library implementation for this data structure yet. But you can find good ones in some open source libraries:
Guava
Apache Commons Collections
Multimap (https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Multimap.html) should help if you are allowed to use it.
Alternatively, you could use Map<Integer, List<Integer>>.
You are using same key (1), which is not what you wanted, unless you wanted to add more values to the same key, in that case have hashtable of list of arrays HashMap<Integer,List<Integer>> integerArrayMap.
In Hashtable, the Key MUST be unique, as you are NOT using unique keys, the same value is being replaced. so try to put the values with different keys.
ht.put(1, 40);
ht.put (2, 60);
I suggest you to refer the Hashtable api here:
https://docs.oracle.com/javase/7/docs/api/java/util/Hashtable.html
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I have the below Java code excert. I am expecting to see the keys printed in a sorted manner (since I am using a TreeMap), but it is not sorting the keys. What I am missing?
CODE:
public class TreeMapTest {
static TreeMap<String,String> li=new TreeMap<String,String>();
static void readAndPrint(){
for (Map.Entry<String, String> entry:li.entrySet() ){
System.out.println(entry);
}
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
String key = String.valueOf(new Random().nextInt(100));
String item = UUID.randomUUID().toString().substring(30);
li.put(key,item);
System.out.println(MessageFormat.format("inserting ({0},{1})",key,item));
}
readAndPrint();
}
}
Sample output:
inserting (7,f4b66a)
inserting (2,5f417d)
inserting (51,90bb9f)
inserting (99,4bfb73)
inserting (41,a4e9d5)
inserting (14,9286d6)
inserting (44,ec4fbd)
inserting (58,e7dd3a)
inserting (69,c54e66)
inserting (0,d1fbfe)
0=d1fbfe
14=9286d6
2=5f417d
41=a4e9d5
44=ec4fbd
51=90bb9f
58=e7dd3a
69=c54e66
7=f4b66a
99=4bfb73
As you see I am not getting the elements sorted ( I sometimes have the output sorted and sometime have it not sorted as above!). What I am missing or misunderstanding?
They are sorted, by the default sort order of Strings. Strings are ordered lexicographically, so "14" is considered less than "2".
If you want numerical sort order, you should have made the keys Integers instead of Strings.
One way of doing it whilst still keeping the keys as Strings would be to use the Treemap(Comparator) constructor:
static TreeMap<String, String> li = new TreeMap<>(Comparator.comparing(Integer::valueOf));
Of course, making the keys Integers also works.
If you want Integer based comparison then you need to have Integer keys in the map. Change
static TreeMap<String,String> li=new TreeMap<String,String>();
to
static TreeMap<Integer,String> li=new TreeMap<Integer,String>();
and , change put method to:
Integer key = new Random().nextInt(100);
String item = UUID.randomUUID().toString().substring(30);
li.put(key,item);
The map is ordering the keys lexicographically because they are strings (1 < 4 for the first character, and so on for the other characters).
The simplest way is to have the keys as Integers:
TreeMap<Integer,String> li=new TreeMap<>();
which will avoid the unnecessary need to convert the integer using String.valueOf.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to store two integer values using an integer key, also please tell how to store and retrieve data using the key.
i already tried this :
static HashMap<Integer, User> nodes = new HashMap<Integer, User>();
public User( int b, int c) {
xco = b;
yco = c;
}
and i stored values into it as
User.nodes.put(User.key,new User((int)upx,(int)upy));
but I can't retrieve the data using the key
First of all your question isn't much describe your requirement and what have you tried so far.
But assuming your question you can try as follows.
you can create a Map<Key,Value> Integer value as a Key and Integer List<Integer> as Value
Map<Integer,List<Integer>> map=new HashMap<>();
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
map.put(1,list);// key is 1, values 1 and 2
you can retrieve values as follows
map.get(1) // will return list which contains values 1 and 2
Edit:
HashMap<Integer, User> nodes = new HashMap<Integer, User>();
User user=new User(1,2);// creating a user
nodes.put(1,user);
Now you can get values
nodes.get(1)// will return user
If I understand the question.
If your values are observably large, you can use the method: v1 * 10^n + v2
where v2 < 10^n
use SparseIntArray it is efficient way to store int key value pair
SparseIntArray sparseIntArray new SparseIntArray();
sparseIntArray.put(int_key,int_value);
while for geting value
sparseIntArray.get(int_key);
use The Map Interface
A map has the form Map <K, V> where:
K: specifies the type of keys maintained in this map.*
V: defines the type of mapped values.
you need to have an object for your 2 integer values:
class Object{
Integer int1;
Integer int2;
}
Map<Integer,Object> map;
To get value
Object result = map.get(1) // will return the first object which contain 2 integers
You can get your 2 integers using Object.int1 and Object.int2