How to perform a group by (sql) in Java - 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.

Related

Best way to compare bunch of Constant Strings (keys) with a Map

So, I have a Map (String, String) which I receive this map can have about 600-800 entries. My task is to retrieve only about 60-120 (based on some logic) of those pairs based on the keys (constant strings).
Right now I have created a List of the required Keys, I am iterating the Map I receive and pulling out required pairs into another Map and passing it on. This works, but the code looks horrible.
There surely has to be a better way of doing this. Any suggestions?
I thought of using contains instead of matching keys, but my requirement is for exact matches. Yes, I read about using RegEx for exact matches, so that can be used as a last resort.
What I need help with:
1. Better way to store required keys than having them in a List. This list of keys are going to be a constant. Having a list of 60-120 strings hardcoded into a List looks horrible.
2. Fastest (time) way to compare the said list and pull out required pairs.
My code:
List <String> keysToCheck = new ArrayList<String>();
keysToCheck.add("attrib1");
...
keysToCheck.add("attribN");
Map<String, String> newMap = new HashMap<String, String>();
for (String key : keysToCheck) {
if(mapRcvd.containsKey(key)) {
newMap.put(key, mapRcvd.get(key));
}
}
I am looking for solutions which would be quicker, as this would be a very small part of a larger application. I am good with having to write a lot of code to achieve that.
You can store all constant keys in a file, where each line contains one key. Then you can get all required keys like:
List<String> requiredKeys = Files.lines(Paths.get(PATH_TO_FILE_WITH_KEYS))
.collect(Collectors.toList());
Now get map with required keys using stream filter method:
Map<String, String> collect = mapRcvd.entrySet().stream() // get stream of map entries
.filter(entry -> requiredKeys.contains(entry.getKey())) // filter only such entries which has required key
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); // collect all filtered entries into new map
More about Collectors.toMap, javadoc
Update: while getting map with required keys may seem more compact, the for-loop with containsKey method in your example is faster than contains. You should probably use the advice #Holger left in the comments

Increment Key in a collection

I have a collection say
Map<Integer,Integer> myMap=new Map<Integer,Integer>();
myMap.put(1,"a");
myMap.put(2,"b");
myMap.put(3,"c");
My map currently has {1="a",2="b",3="c"}.
Suppose I want to put a value say myMap.put(1,"d")
So is there a way that I am able to add the existing key and incrementing the remaining key so my output map be like
{1="d",2="a",3="b",4="c"} ?
You will have to iterate over all the elements of the Map in order to modify the values for all the existing keys.
For example, woth Java 8 Streams you can produce a new Map where the keys are incremented, and then add the new Entry :
map = map.entrySet().stream().collect(Collectors.toMap(e->e.getKey()+1,e->e.getValue()));
map.put(1,"d");
However, if your keys are consecutive integers (as your example suggests), why not use an ArrayList<String> instead of a Map<Integer,String>? This will give you the functionality you want by simply calling list.add(0,"d"); (with the small difference of the indices starting at 0 instead of 1).

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.

How to store several values to one key (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.

How to get all the entries from a LinkedHashMap in Java?

I am using String object as the key to a linkedhashmap.
How can I get all the entries in the LinkedHashMap?
You have three options that depend on whether you need just keys, just values or both
Set<String> keys = yourMap.keySet();
Collection<YourValueClass> values = yourMap.values();
Set<Map.Entry<String,YourValueClass>> pairs = yourMap.entrySet();
then you can easily iterate over them if you need. Actually all of them allow iterating using a simple foreach loop:
for (Map.Entry<String,YourClassValue> e : yourMap.entrySet())
// do something
You can use the entrySet method, which returns a set containing the key-value pairs in your map.

Categories