Does java have a Frequency table? - java

Does Java have a built in Frequency Table? I remember using one in one of my classes and I know Python has one, but I do not remember if I built one on my own or if Java has one for use.

I assume by "frequency table" you mean a map of value-to-count.
The answer is no.
It's not much of a stretch to create a well-behaved one though:
Map<T, Integer> freq = new HashMap<T, Integer> () {
#Override
public Integer get(Object key) {
return containsKey(key) ? super.get(key) : 0;
}
}
Then when using you don't have to clutter your code with null checks when getting a frequency:
freq.get(value); // returns zero for not found
Or when incrementing:
freq.put(value, freq.get(value) + 1); // always works, won't throw NPE etc

Not built-in but you can check Apache Commons Statistics. It has an easy Frequency table builder that allows to find frequency, cumulative frequency, counts, etc.

Related

Alternative to multiple nested for and if blocks

I'm trying to implement a complicated block that I've written using multiple for loops and if conditions to something much less convoluted. The initial code is
for(Coll_Monthly_Main monthlyAccount:monthlyList){
for(Coll_Daily_Main dailyAccount:dailyList){
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
for(Catg_Monthly monthlyCategory: monthlyAccount.getCatg()){
for(Catg_Daily dailyCategory: dailyAccount.getCatg()){
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
for(SecCatDtl_Daily dailySecCategory:dailyCategory.getSecCatDtl()){
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
}
}
}
}
return monthlyList;
I've followed this answer and have managed to implement the first level as below:-
monthlyList.forEach(coll_mthly->{
dailyList.stream().filter(coll_daily->coll_mthly.getAccountId().trim().equals(coll_daily.getAccountId().trim()))
.forEach(catg_mth->coll_mthly.getCatg())->{
};
});
For the next level of nesting, I need to loop over a nested list and I'm not sure how to proceed about it. I keep getting a syntax error as follows:-
Syntax error on tokens, TypeElidedFormalParameter expected instead
I'd appreciate any pointers in the right direction.
Update:-
This is how it looks like following Thomas' answer
Map<String, Coll_Daily_Main> dailies = dailyList.stream().collect(Collectors.toMap(cdm -> cdm.getAccountId(), cdm-> cdm) );
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Coll_Daily_Main dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim());
Map<String, Catg_Daily> dailyCatgories=dailiesForAccount.getCatg().stream().collect(Collectors.toMap(cv->cv.getPriCatId(), cv->cv));
for(Catg_Monthly monthlyCategory:monthlyAccount.getCatg()){
Catg_Daily dailyCategory = dailyCatgories.get(monthlyCategory.getPriCatId().trim());
if(dailyCategory!=null){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
Map<String,SecCatDtl_Daily> dailySecCategories=dailyCategory.getSecCatDtl().stream().collect(Collectors.toMap(fg->fg.getCatId(), fg->fg));
for(SecCatDtl_Mthly monthlySecCategory:monthlyCategory.getSecCatDtl()){
SecCatDtl_Daily dailySecCategory =dailySecCategories.get(monthlySecCategory.getCatId().trim());
if(dailySecCategory!=null){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
}
}
}
As the others already stated multiple times it's most likely better to rethink your approach and make it not even more readable but faster as well. One thing that comes to my mind: you have 3 levels that consist of 2 loops and an if to check whether the elements match (by id). Those levels will have O(n*m) complexity.
However, you could try to build a map or multimap (Guava has some) with the id as the key and get it down to O(n + m):
O(n) for building the map (ideally on on the larger set, i.e. daily)
O(m) for iterating over the second set (ideally the smaller set, i.e. monthly)
Lookups should be O(1) so can be ignored
I'm not sure what all those nested levels mean so I only can give an example of what you could do for one level (I'll take the first):
//I'm using Google Guava's classes here
SetMultimap<String, Coll_Daily_Main> dailies = ...;//use one that fits your needs
//Iterate over n daily entries and put them into the map which should be O(n)
dailyList.forEach( cdm -> dailies.put( cdm.getAccountId().trim(), cdm ) );
//Iterate over the (smaller) set of monthly entries and do a lookup for the dailies which should be O(m)
for(Coll_Monthly_Main monthlyAccount : monthlyList) {
Set<Coll_Daily_Main> dailiesForAccount = dailies.get( monthlyAccount.getAccountId().trim() );
//level done, either go down to the next or try to further straighten it out or optimize
}
Update:
I forgot to mention that you'd not have to use Guava with Java 8. Though the definition looks a little more awkward using a Map<String, Set<Coll_Daily_Main>> isn't that "hard" anymore:
Map<String, Set<String>> dailies = new HashMap<>();
dailyList.forEach( cdm -> dailies.computeIfAbsent( cdm.getAccountId().trim(), v -> new HashSet<>() ).add( cdm ) );
Note: you could also use collectors to make it a little shorter and in one line. Whether that's easier to read and use is up to debate.
Map<String, Set<Daily>> dailies =
dailyList.stream().collect( Collectors.groupingBy( cdm -> cdm.getAccountId().trim(),
Collectors.toSet() ) );
First you need to extract all your if statements in private methods.
Then you can start to refactor your for statements with lambdas.
You could even declare a static function (called loop in the example below) to export your nested loops logic:
public class Test {
public List<Coll_Monthly_Main> runThatThing(List<Coll_Monthly_Main> monthlyList, List<Coll_Daily_Main> dailyList) {
loop(monthlyList, dailyList, Test::updateMonthlyCategories);
return monthlyList;
}
private static void updateMonthlyCategories(Coll_Monthly_Main monthlyAccount, Coll_Daily_Main dailyAccount) {
if(monthlyAccount.getAccountId().trim().equals(dailyAccount.getAccountId().trim())){
loop(monthlyAccount.getCatg(), dailyAccount.getCatg(), Test::updateMonthlyCategory);
}
}
private static void updateMonthlyCategory(Catg_Monthly monthlyCategory, Catg_Daily dailyCategory) {
if(monthlyCategory.getPriCatId().trim().equals(dailyCategory.getPriCatId().trim())){
monthlyCategory.setMthTtl(dailyCategory.getMthTtl());
monthlyCategory.setMtd(dailyCategory.getMtd());
monthlyCategory.setYtd(dailyCategory.getYtd());
loop(monthlyCategory.getSecCatDtl(), dailyCategory.getSecCatDtl(), Test::updateMonthlySecondCategory);
}
}
private static void updateMonthlySecondCategory(SecCatDtl_Mthly monthlySecCategory, SecCatDtl_Daily dailySecCategory) {
if(monthlySecCategory.getCatId().trim().equals(dailySecCategory.getCatId().trim())){
monthlySecCategory.setMthTtl(dailySecCategory.getMthTtl());
monthlySecCategory.setMtd(dailySecCategory.getMtd());
monthlySecCategory.setYtd(dailySecCategory.getYtd());
}
}
// nested loops through list1 and list2 which apply the function `f` to all pairs.
//Using a BiConsumer because the f methods we use always return void
private static <T, U> void loop(List<T> list1, List<U> list2, BiConsumer<T, U> f) {
list1.forEach(
element1 -> list2.forEach(
element2 -> f.accept(element1, element2)
));
}
}

Java HashMap Get Values (the most of which value)

Hi so a strange question...
Let's start with a simple description of the code:
I have a hashmap filled with <PlayerUUID, KingdomUUID>
Where the playerUUID is the key in the hashmap (obviously)
Now for my capture process system I need to determine how many of the diffrent values there is and thus which has the most.
For example:
3 players are attacking a point, 2 players are in ORION kingdom, 1 in Erion.
I need to check the values of the hashmap to see which of the kingdoms has the most attackers. (ORION is the answer)
Regards,
Thomas
I hope this description was good enough if not ask away!
You can do what f1sh did. However, Java 8 added streams and lambdas, which you can use as well. The resulting code is more compact, more readable, and less error prone. This code will be a bit slower, however you probably won't even feel it unless you deal with a lot of values.
public KingdomUUID getMax(HashMap<PlayerUUID, KingdomUUID> inputMap) {
return inputMap.entrySet()
.stream()
.max((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? 1 : -1)
.get()
.getValue();
}
More about Java 8 streams.
More about Java 8 lambdas.
Use this method:
Entry<KingdomUUID, Integer> getMax(Map<PlayerUUID, KingdomUUID> input) {
Map<KingdomUUID, Integer> r = new HashMap<>();
for(KingdomUUID kingdom:input.values()){
final Integer old = r.get(kingdom);
r.put(kingdom, old==null?1:old+1);
}
Map.Entry<KingdomUUID, Integer> max = null;
for(Map.Entry<KingdomUUID, Integer> e:r.entrySet()){
if(max==null || e.getValue()>max.getValue()){
max = e;
}
}
return max;
}
You can use getKey() on the return object to see which KingdomUUID occurs most often and and getValue() how many times.

Get total for unique items from Map in java

I currently have a map which stores the following information:
Map<String,String> animals= new HashMap<String,String>();
animals.put("cat","50");
animals.put("bat","38");
animals.put("dog","19");
animals.put("cat","31");
animals.put("cat","34");
animals.put("bat","1");
animals.put("dog","34");
animals.put("cat","55");
I want to create a new map with total for unique items in the above map. So in the above sample, count for cat would be 170, count for bat would be 39 and so on.
I have tried using Set to find unique animal entries in the map, however, I am unable to get the total count for each unique entry
First, don't use String for arithmetic, use int or double (or BigInteger/BigDecimal, but that's probably overkill here). I'd suggest making your map a Map<String, Integer>.
Second, Map.put() will overwrite the previous value if the given key is already present in the map, so as #Guy points out your map actually only contains {cat:55, dog:34, bat:1}. You need to get the previous value somehow in order to preserve it.
The classic way (pre-Java-8) is like so:
public static void putOrUpdate(Map<String, Integer> map, String key, int value) {
Integer previous = map.get(key);
if (previous != null) {
map.put(key, previous + value);
} else {
map.put(key, value);
}
}
Java 8 adds a number of useful methods to Map to make this pattern easier, like Map.merge() which does the put-or-update for you:
map.merge(key, value, (p, v) -> p + v);
You may also find that a multiset is a better data structure to use as it handles incrementing/decrementing for you; Guava provides a nice implementation.
As Guy said. Now you have one bat, one dog and one cat. Another 'put's will override your past values. For definition. Map stores key-value pairs where each key in map is unique. If you have to do it by map you can sum it just in time. For example, if you want to add another value for cat and you want to update it you can do it in this way:
animals.put("cat", animals.get("cat") + yourNewValue);
Your value for cat will be updated. This is for example where our numbers are float/int/long, not string as you have. If you have to do it by strings you can use in this case:
animals.put("cat", Integer.toString(Integer.parseInt(animals.get("cat")) + yourNewValue));
However, it's ugly. I'd recommend create
Map<String, Integer> animals = new HashMap<String, Integer>();

Not entirely clear on what this code does? (Includes Set, HashMap and .keySet())

So I've finished a program and have had help building it/worked with another person. I understand all of the program in terms of what each line of code does except one part. This is the code:
Set<String> set1 = firstWordGroup.getWordCountsMap().keySet();
Map<String, Integer> stringIntegerMap1 = set1.stream().collect(HashMap::new,
(hashMap, s) -> hashMap.put(s, s.length()), HashMap::putAll);
stringIntegerMap1.forEach((key,value) ->System.out.println(key + " : "+value));
Some background info:
getWordCut is a method that looks like this:
public HashMap getWordCountsMap() {
HashMap<String, Integer> myHashMap = new HashMap<String, Integer>();
for (String word : this.getWordArray()) {
if (myHashMap.keySet().contains(word)) {
myHashMap.put(word, myHashMap.get(word) + 1);
} else {
myHashMap.put(word, 1);
}
}
return myHashMap;
}
firstWordGroup is a constructor that stores a string of words.
If anybody could explain exactly what this block of code does and how it does it then that would be helpful, thanks.
P.S: I'm not sure if supplying the whole program to reproduce the code is relevant so if you think it is, just leave a comment saying so and I will edit the question so you can reproduce the program.
getWordsCountsMap() returns a map where the key is a word and the value is how many times the word occurred in the array
Set<String> set1 = firstWordGroup.getWordCountsMap().keySet();
The .keyset() method returns just the keys of the map, so now you have a set of the words, but have lost the occurrence counts.
Map<String, Integer> stringIntegerMap1 =
set1.stream()
.collect(HashMap::new,
(hashMap, s) -> hashMap.put(s, s.length()),
HashMap::putAll)
This is using Java8 streams to iterate through the set (words) originally put into a map and create a new hash map, where the key is the word (as it was before) and the value is the length of the word (whereas originally it was the word count). A new hash map is created and populated and returned.
What I'm not understanding is the final HashMap::putAll() which would seem to take the hashmap just populated and re-add all entries (which really would be a no-op because the keys would be replaced). Since I haven't whipped open my IDE to put in the code and test it (which, if you haven't yourself, would recommend, I'm just not interested enough to do so because it's not my problem!).
stringIntegerMap1.forEach((key,value) ->System.out.println(key + " : "+value));
In essence, this is a cleaner way to iterate through the entries in the map created, printing out the word and length for each.
After working through this and thinking about it, I have a feeling I'm doing your homework for you, the real way to figure this out is to break things down and debug through your IDE and seeing what each step of the way does.
Set<String> set1 = firstWordGroup.getWordCountsMap().keySet();
This line calles getWordCountsMap which returns a map from words to their count. It then ignores the count and just takes the words in a set. Note this could be achieved in a lot of much simpler ways.
Map<String, Integer> stringIntegerMap1 = set1.stream()
.collect(HashMap::new, (hashMap, s) -> hashMap.put(s, s.length()), HashMap::putAll);
This converts the set of words to a stream and then collects the stream. The collector starts by creating a hash map then, for each word, adding a map from the to its length. If multiple maps are created (as is allowed in streams) then they are combined using putAll. Again there are much simpler and clearer ways to achieve this.
stringIntegerMap1.forEach((key,value) ->System.out.println(key + " : "+value));
This line iterates through all entries in the map and prints out the key and value.
All this code could have been achieved with:
Arrays.stream(getWordArray())
.distinct().map(w -> w + ":" + w.length()).forEach(System.out::println);
This command converts the words to a stream, removes duplicates, maps the words to the output string then prints them.

What Java data structure is best for two-way multi-value mapping

I'm relatively new to Java and I have a question about what type of data structure would be best for my case. I have a set of data which are essentially key-value pairs, however each value may correspond to multiple keys and each key may correspond to multiple values. A simplified example would be:
Red-Apple
Green-Apple
Red-Strawberry
Green-Grapes
Purple-Grapes
Considering the above example, I need to be able to return what color apples I have and/or what red fruits I have. The actual data will generated dynamically based upon an input file where each set will be anywhere from 100-100,000 values and each value may correspond to hundreds of values in the other set.
What would be the most efficient way to store and parse this data? I would prefer a solution as native to java as possible rather than something such as an external database.
This question is related, but I'm not sure how to apply the solution in my case given that I would need to assign multiple values to each key in both directions.
As you can't have duplicate keys in a Map, you can rather create a Map<Key, List<Value>>, or if you can, use Guava's Multimap.
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("Red", "Apple");
multimap.put("Red", "Strawberry");
System.out.println(multimap.get("Red")); // Prints - [Apple, Strawberry]
But the problem is you can't ask for the keys of a given object, I'll keep looking and make and edit if I find something else, hope it helps.
Still, you can make the reverse yourself by iterating the map and finding the keys for the object.
I suggest you use Guava's Table structure. Use color as your row keys and fruit as your column key or the other way round. Specifically, HashBasedTable is well suited for your case.
As per your use case, you wouldn't need to store anything for the values. However, these Tables don't allow null values. You could use a dummy Boolean or any other statistical useful value, i.e. date and time of insertion, user, number of color/fruit pairs, etc.
Table has the methods you need, such as column() and row(). Bear in mind that the docs say that these structures are optimized for row access. This might be OK for you if you plan to access by one key more than by the other.
You can create your own custom data structure
public class MultiValueHashMap<K, V> {
private HashMap<K, ArrayList<V>> multivalueHashMap = new HashMap<K, ArrayList<V>>();
public static void main(String[] args) {
MultiValueHashMap<String, String> multivaluemap = new MultiValueHashMap<String, String>();
multivaluemap.put("Red", "Apple");
multivaluemap.put("Green", "Apple");
multivaluemap.put("Red", "Strawberry");
multivaluemap.put("Green", "Grapes");
multivaluemap.put("Purple", "Grapes");
for(String k : multivaluemap.keySet()){
System.out.println(k + " : " + multivaluemap.get(k).toString());
}
}
public void put(K key, V value){
if (multivalueHashMap.containsKey(key)){
ArrayList<V> values = multivalueHashMap.get(key);
values.add(value);
}else{
ArrayList<V> values = new ArrayList<V>();
values.add(value);
multivalueHashMap.put(key, values);
}
}
public Set<K> keySet(){
return multivalueHashMap.keySet();
}
public ArrayList<V> get(K key){
return multivalueHashMap.get(key);
}
}
The output should be
Red : [Apple, Strawberry]
Purple : [Grapes]
Green : [Apple, Grapes]

Categories