Java- Adding unique values to Hashmap - java

ok,
here is my issue....I have a List<short>letterList which has for example: "1,2,3,4,5,6,7,8,9,10"
What Im doing is Im iterating over this list then passing the value into another method which returns a value:
so:
string value = null;
for(Short foo : letterList)
{
value = getSomeValue(foo) //returns a letter A or B or C
}
What Im trying to do is get a hashmap to look something like this:
key: a, value 1,5,7
key b, value: 2,3,4
key c, value: 6,8,9,10
not these values specifically, but you get my point
Im not sure how to do this I have tried creating a map with a <set<string>, List<short>
any suggestions would be appreciated

HashMap<Character, List<Short>> map
My understanding was you were looking for a simple way to store a list of values with a character? If so, use that above.
If you want to sort by letter (for easy printing out) use the following:
TreeMap<Character, List<Short>> map
You can get and of the values by using map.get('A') and using your standard methods to iterate through or get a certain value from the associated list.

Java has no built-in MultiMap, but you can either simulate a multimap (Map<String, List<Short>>) or try out Guava for example: https://code.google.com/p/guava-libraries/

Map<String, List<Short>>
The key (String) will be unique. The List<> will be able to hold a list of shorts.
If you want to make sure the numbers are unique as well as the keys, then use a Set instead of a list.
Remember to initialize the lists you put in the map (getting a key like "A" for the first time will return null, so check if it's null and if it is then create a List, put your value into it, and put the list into the map).

Not knowing your complete use case, I would suggest having a different look at your data structure organization. e.g.
Map<Integer, String> map = new HashMap<Integer, String>();
Where the keys are 1,2....10 as in your example and the values are
1 -> a
2 -> b
3 -> b
etc.
To get your original "list" you can use -
Set<Integer> numbers = map.keySet();

Related

Why can I update a hash map list value with a get and add function?

Can someone clarify why I am able to update map1 key "phone" with simply a get function to retrieve the list and then an add function to append to the list? Don't I need to use put to update the value in the map with the changes from the previous steps?
HashMap<String, List<String>> map1 = new HashMap<String, List<String>>();
ArrayList<String> phone = new ArrayList<>();
phone.add("201");
map1.put("phone", phone);
map1.get("phone").add("551"); // Confusion on how this updates the value without having to use a put function for the map
In this example for map2, I had to use a put function to update what was existing in the map for the key "hi".
HashMap<String, Integer> map2 = new HashMap<>();
map2.put("hi", 0);
map2.put("hi", map2.get("hi") + 1);
Ultimately, I'm trying to understand why these two different maps don't both use put to update the map values.
Why I am able to update map1 key "phone" with simply a get function?
Answer: Actually this is not like that. In this hashmap, your key is String and your value is a list of strings.
When you pick an elment from the map using .get method this time it returns your value, here a list of strings.
Now, as you get the list reference, you can do any list operation on that list. Here you add "551" to the list.
So, now your key-value pair map looks something like this.
Key(String) Value(List<String>)
---------- ------------------
phone [201,551]
For map2, I had to use a put function to update?
Answer: This time you have a map, where key - String and value - Integer.
When you get("hi") it return integer 0.
You can not perform add, remove... type operation in an Integer type.

clear all values of hashmap except two key/value pair

I have a HashMap with hundred of key/value pairs.
Now I have to delete all key/values except 2 key/value.
I have use this way :
if(map!=null){
String search = map.get(Constants.search);
String context = map.get(Constants.context);
map = new HashMap<>();
map.put(Constants.search,search);
map.put(Constants.context,context);
}
But java 8 introduced removeIf() for these kind of condition. How can I solve this problem with removeIf() method ?
You'll need to it like this :
map.keySet().removeIf(k -> !(k.equals(Constants.search) || k.equals(Constants.context)));
It will iterate over the keys and remove the ones for those the key is not one of or two required keys
yet shorter (since Java 2):
map.keySet().retainAll(myKeys);
Since keySet() still wraps the original HashMap, its #retainAll() affects the Map.
myKeys is a collection of keys, e.g.: myKeys = List.of("key1", "key2")

Is there an efficient way of checking if HashMap contains keys that map to the same value?

I basically need to know if my HashMap has different keys that map to the same value. I was wondering if there is a way other than checking each keys value against all other values in the map.
Update:
Just some more information that will hopefully clarify what I'm trying to accomplish. Consider a String "azza". Say that I'm iterating over this String and storing each character as a key, and it's corresponding value is some other String. Let's say I eventually get to the last occurrence of 'a' and the value is already be in the map.This would be fine if the key corresponding with the value that is already in the map is also 'a'. My issue occurs when 'a' and 'z' both map to the same value. Only if different keys map to the same value.
Sure, the fastest to both code and execute is:
boolean hasDupeValues = new HashSet<>(map.values()).size() != map.size();
which executes in O(n) time.
Sets don't allow duplicates, so the set will be smaller than the values list if there are dupes.
Very similar to EJP's and Bohemian's answer above but with streams:
boolean hasDupeValues = map.values().stream().distinct().count() != map.size();
You could create a HashMap that maps values to lists of keys. This would take more space and require (slightly) more complex code, but with the benefit of greatly higher efficiency (amortized O(1) vs. O(n) for the method of just looping all values).
For example, say you currently have HashMap<Key, Value> map1, and you want to know which keys have the same value. You create another map, HashMap<Value, List<Key>> map2.
Then you just modify map1 and map2 together.
map1.put(key, value);
if(!map2.containsKey(value)) {
map2.put(value, new ArrayList<Key>);
}
map2.get(value).add(key);
Then to get all keys that map to value, you just do map2.get(value).
If you need to put/remove in many different places, to make sure that you don't forget to use map2 you could create your own data structure (i.e. a separate class) that contains 2 maps and implement put/remove/get/etc. for that.
Edit: I may have misunderstood the question. If you don't need an actual list of keys, just a simple "yes/no" answer to "does the map already contain this value?", and you want something better than O(n), you could keep a separate HashMap<Value, Integer> that simply counts up how many times the value occurs in the map. This would take considerably less space than a map of lists.
You can check whether a map contains a value already by calling map.values().contains(value). This is not as efficient as looking up a key in the map, but still, it's O(n), and you don't need to create a new set just in order to count its elements.
However, what you seem to need is a BiMap. There is no such thing in the Java standard library, but you can build one relatively easily by using two HashMaps: one which maps keys to values and one which maps values to keys. Every time you map a key to a value, you can then check in amortized O(1) whether the value already is mapped to, and if it isn't, map the key to the value in the one map and the value to the key in the other.
If it is an option to create a new dependency for your project, some third-party libraries contain ready-made bimaps, such as Guava (BiMap) and Apache Commons (BidiMap).
You could iterate over the keys and save the current value in the Set.
But, before inserting that value in a Set, check if the Set already contains that value.
If this is true, it means that a previous key already contains the same value.
Map<Integer, String> map = new HashMap<>();
Set<String> values = new HashSet<>();
Set<Integter> keysWithSameValue = new HashSet<>();
for(Integer key : map.keySet()) {
if(values.contains(map.get(key))) {
keysWithSameValue.add(key);
}
values.add(map.get(key));
}

What is a efficient way to condense a List of objects to based on an object value?

I have an ArrayList of Objects. The object has five fields: id, date, name, value, adjusted_value. The list may hold multiple entries with the same name, and I am having trouble devising an efficient way to condense the list based on the name to where I will a list of similar objects but the values stored will be name, sum(value), sum(adjusted_value).
Is there an efficient way to do this? My current method has for loops inside of a do-while.
Clarfication:
I have a list of obejcts :
{id,date,name,value,ajusted_value},
{1,"10/30/2014","peaches",4,3}
{2,"10/30/2014","apples",2,2}
{3,"10/31/2014","peaches",3,1}
.
.
.
I want to condense to list based the name value to one that looks like this:
{null,null,"peaches",7,4}
{null,null,"apples",2,2}
.
.
.
However, I found that HashMap's put() functionality will perform what I desire automatically, but now I need to do this sort of action in Javascript if possible.
You can define a Map where the key is the name and value is the object instance.
Go through the list and for each instance check whether it exists in the map.
If not just add to the map. map.put(instance.name,instance)
If it's already added to the map just
mapInstance=map.get(instance.name);
mapInstance.value+=instance.value;
mapInstance.adjusted_value+=instance.adjusted_value;
After the loop you have the filled map with grouped data
I would use Guava in two step. Use a NameFunction to convert the list to a Multimap. Use a CondenseFunction to convert the values of the Multimap.
Function<MyClass, String> toName = new Function(){
public String apply(MyClass input){return input.name;}};
ImmutableListMultimap<String, MyClass> multimap = Multimaps.index(myList, toName);
Map<String, Collection<MyClass>> map = multimap.asMap();
Function<Collection<MyClass>, MyClass> condense= new Function(){
public MyClass apply(Collection<MyClass>input){
// create sums here
}};
Map<String, MyClass> condensed = Maps.transformValues(map, condense);
Collection<MyClass> result = condensed.getValues();
Multimaps.index()
Maps.transformValues

How to initiate multidimensional arraylist with different objects?

I'm having trouble trying to initiate an arraylist in which the first column I want to be a string, and the second column be a custom object.
For example column [0] be String, and column[1] be an Integer. Convention attempts of creating a multidimensional arraylist as in those used by int[][] or String[][] don't seem to work :( I would welcome any help. At this point I don't think it's something java allows. I can make it work for just one type of object but it's not what I want. Thanks!
Do you need an arraylist? You could create a Map<String, Object> or Map<String, Integer> or whatever you need..
Sure it does, but you weaken/eliminate type-checking:
Map myMap<String>, Integer> myData = new HashMap<String, Integer>();
Now your list of strings can be retrieved by myMap.keySet() and values can be retrieved by myMap.values(). Each of these return a Set, which you can easily convert to a List using the following code:
List<String> strings = new ArrayList<String>(myMap.keySet()); // get your strings
List<Integer> numbers = new ArrayList<Integer>(myMap.values(); // get your numbers
Good luck and if you should run into problems, do leave a comment.
Arrays are geared towards one specific type of thing - be they Object or String or int. Despite the fact that you're adding multiple dimensions to them, they still only hold one type of information.
What you would rather have is a mapping between two objects. This allows you to do the following:
Associate any key to a particular value
Eliminate duplicate key entries
Be much easier to access instead of array indexing
Here's an example. Say your custom object is a Cat, and you want to map the name of the owner to a particular Cat. You create a new instance of a Map.
Map<String, Cat> catOwners = new HashMap<>();
You can then put elements into it...
catOwners.put("Jamie", new Cat("Tycho"));
...and retrieve them with relative ease.
Cat currentCat = catOwners.get("Jamie"); // gets Jamie's cat
if you really want to, you can even iterate over them using the Map.Entry object provided with all Maps:
for(Map.Entry<String, Cat> element : catOwners.entrySet()) {
System.out.println(element.getKey()
+ " owns " + element.getValue().getName());
}
What you can do is use the generic Object type, and cast accordingly.

Categories

Resources