How to store several values to one key (java) - java

I search for a datastructure, where I can store several key-value pairs.
The data essentially looks like this:
(1 , value_1)
(2 , value_2)
So I thought of using HashMap. Sadly this won't work for me, because multiple values to one key can occur.
(In the example above:
(1 , value_2)
might be another entry )
Is there any way of performantly storing this data, except creating a List with a new Object or something like this.
get(1)
should return value_1 and value_2 as a list or set or anything similar.
Thanks in advance

I think the data strucure you're looking for is in google's guava library, MultiMap. See http://guava-libraries.googlecode.com/svn-history/r13/trunk/javadoc/com/google/common/collect/Multimap.html.
Basically it's a Map<K,Collection<V>> but with an easier to use interface.

If the keys are integers and the values are e.g. strings, and the values belonging to one key are different, you could use e.g. the plain Java structure:
Map<Integer, HashSet<String>> container = new HashMap<Integer, HashSet<String>>();
void add(Map<Integer, HashSet<String>> container, int key, String value) {
HashSet<String> values = container.get(key);
if (values == null) {
values = new HashSet<String>();
}
values.add(value);
container.put(key, values);
}

You could use HashMap<Integer,Set<T>> or HashMap<Integer,List<T>>, where T is the type of value_1, value_2 etc.
Basically, get would do what you want out of the box. Adding elements is a little bit more cumbersome; you could write a short wrapper function to make it nicer.

Related

**EMERGE** (Java) Hashmap single key multi values, locate key in multi values Node

The code below just to demonstrate an example of my code.
LinkedHashMap<String, String> studentID = new LinkedHashMap<String, String>();
//studentID.put("P01", "P06" + "P07");
studentID.put("P02", "P08" + "P09");
studentID.put("P03", "P10");
studentID.put("P04", "P11");
studentID.put("P05", "P12");
System.out.println(studentID.containsValue(P06));
So what I am struggling here is when there are multiple values in hashmap, Java will not be able to put up individual value as human do, for instance, System.out.println(studentID.containsValue(P06));, I am trying to locate P06 only but the program will display false as in it cannot pick up multiple values, in fact, it merged multiple values into one. Does anyone knows any solutions the I can search a single value when that value is based in a multi-values hashmap, and also but break when comes to using a key to search and allocate all values in the line, thank you.
You can use the stream API.
boolean found = studentID.values().stream().
anyMatch(value -> value.contains("P06"));
System.out.println(found);

How to iterate and remove keys from Map<String , Map<String, Set<String>>>

I am having map this way,
Map<String, Map<String, Set<String>>> sampleMap = new Map<String, Map<String, Set<String>>>();
and the data in this map would be this way,
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2], 2016={A=[1,2], B=[3,4]}};
I want to remove the key's from the map based on this input: List<String> filter; with values this way,
filterArray : [2014, 2015]
i.e, first iterate through arraylist values one by one, verify if the arraylist value matches with any of the key in Hashmap.
if key is matched ignore it.
if key is not matched, I just want to remove that key from the map.
i.e, I always want to keep only matched keys in map, comparing with the input value passed.
In this case, as I have arraylist values this way,[2014,2015],
2014,2015 keys only to be in my map. So,
Data to be before removal:
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2], 2016={A=[1,2], B=[3,4]}};
Data to be after removel:
sampleMap={2014={A=[1, 2], B=[3], 2015={A=[1,2], B=[1,2]}};
I tried this way, However I just want to know is this is the correct approch, or is it is prone to any of the exceptions?
Iterator<Map.Entry<String , Map<String, Set<String>>>> iter = sampleMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String , Map<String, Set<String>>> entry = iter.next();
logger.info("Keys : " + entry.getKey());
if (filterArray.equalsIgnoreCase(entry.getKey())) {
iter.remove();
}
}
Use retainAll() on the keySet:
map.keySet().retainAll(list);
Seems reasonable. I might have a couple pieces of advice.
First of all, whenever I see nested collections I always wonder if there should be a class or two in there. If this is a one-time task then don't worry about it, but if you want to reuse this code you might want to think about creating a class for your inner map/set... but if it's really this simple then it's no big deal.
Secondly if you are using Java 8, using a list comprehension for filtering would perform better (Because it would automatically thread your compares) and would be cleaner. I can give you the groovy solution for what you are trying to do, but I'm not familiar enough with java 8 list comprehensions to do it correctly.
def filteredStructure=structure.findAll{entry->entry.key.equalsIgnoreCase("2014") || entry.key.equalsIgnoreCase("2015"))
The java version should be really similar.

Get a list of key's in HashMap having key like 'some value'

In Mysql we can query a table having clause " WHERE name LIKE '%someName%' ", can we have the same functionality with HashMap in java,if so how can we achieve this more efficiently in a less time by not iterating over each element?
If you're using Java SE 8 and the new Streams API: there is a filter method which basically is what you are looking for, I think.
e.g. something like (untested!):
myMap.entrySet().stream().filter(entry -> entry.getKey().contains("someName")).map(entry -> entry.getValue()).collect(Collectors.toList());
You can iterate on all your keys and check if they match a regexp. This might not be the most efficient way of doing it, but it's the first thing I thought of.
Here is what it would look like:
Pattern p = Pattern.compile("*someName*"); // the regexp you want to match
List<String> matchingKeys = new ArrayList<>();
for (String key : map.keySet()) {
if(p.matcher(key).matches()) {
matchingKeys.add(key);
}
}
// matchingKeys now contains the keys that match the regexp
Note: map is supposed to be declared earlier like this:
HashMap<String, SomeValueClass> map = new HashMap<>();
Remove all values which doesn't contain key part:
yourMap.keySet().removeIf(key -> !key.contains(keyPart));
Or regex:
yourMap.keySet().removeIf(key -> !key.matches(".*keyPart.*"));
There may be a way to achieve this functionality in Java, but HashMap will not do it.
If you want to get all the values in a map that are associated to a given key you are doing a reverse lookup.
You would need to iterate over every key / value pair in the map, searching for the given value and storing it into a collection. Something like this:
List<KeyType> keys = new ArrayList<>();
for (Map.Entry<KeyType, ValueType> e : myMap)
if(e.getValue().equals(valueWeAreSearchingFor)) keys.add(e.getKey());

Share values between several transformations?

Imagine I have the following List of values:
List<String> values = Lists.asList("a", "a", "b", "c");
Now I want to add an index to all values, so that one ends up with this as list:
a1 a2 b1 c1 // imagine numbers as subscript
I want to use a FluentIterable and its transform method for that, so something like this:
from(values).transform(addIndexFunction);
The problem with that is, that addIndexFunction needs to know, how often the index was already increased - think of a2, when adding the index to this a, the function needs to know, that there was alraedy an a1.
So, is there some kind of best practice for doing such a thing? My current idea is to create a Map with each letter as key, so:
Map<String,Integer> counters = new HashMap<>();
// the following should be generated automatically, but for the sake of this example it's done manually...
counters.put("a", 0);
counters.put("b", 0);
counters.put("c", 0);
and then modify my transform call:
from(values).transform(addIndexFunction(counters));
As Map is an object and passed by reference, I can now share the counter state between the transformations, right? Feedback, better ideas? Is there some built-in mechanism for such things in Guava?
Thanks for any hint!
Use a Multiset to replace the HashMap, and you're good to go, following #Perception's suggestion to encapsulate the Multiset in the Function itself and aggregating data as the function is applied.
Don't use transform here, or your iterable will have different values every time you iterate over it, and will generally behave very weirdly. (It's also somewhat frowned upon to have state in a Function.)
Instead, do a proper for loop with a Multiset helper:
Multiset<String> counts = HashMultiset.create();
List<Subscript> result = Lists.newArrayList();
for (String value : values) {
int count = counts.add(value, 1);
result.add(new Subscript(value, count));
}

How to perform a group by (sql) in Java

I have a text file which looks like this:
code appearance
----------------
j4t8 1
fj89 3
pf6n 1
j4t8 5
And I want to sort by the codes which appear the most. As you can see (and since I want to perform a group by) there are duplicate codes, so using HashMap would be a problem (duplicate keys). Any ideas?
don't know if this is the best solution but you could create a map of a list like this:
Map<String, List<Integer>> map = new HahsMap<String, List<Integer>>();
if(map.contains.(key))
{
map.get(key).add(new_appearance_value);
}
else
{
List<Integer> app = new ArrayList<Integer>();
app.add(new_appearance_value);
map.put(key, app);
}
Where the map key would be the code and the values of appearance would go into the list.
Note: to determine which code has more appearances just check for the size of the list of each code.
You can use
HashMap map = new HashMap<String, List<Integer>>();
The appearances will be stored in a list associated with every code.
Then given a code you just retrieve the list of integers and iterate over it.
You need a Collection of Pair objects. Each pair holds the code and the appearance. You then sort the collection using a Comparator, which only compares the appearance in each Pair object, and disregards the code.
The Commons Collections MultiValueMap can be used to decorate another map, allowing it to have more than one value for a key.

Categories