HashMap Keys and Value comparison [closed] - java

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 7 years ago.
Improve this question
I'm comparing HashMap value against the keys and replace if key is larger. The purpose is to update Finger Table of Chord System simulation.
I have HashMap data:
Key 0 with Values: [1,2,4,8,16]
Key 3 with Values: [4,5,7,11,19]
Key 7 with Values: [8,9,11,15,23]
The desired outcome is such that for each key 0, 3 and 7, its values will be compared with the next key value.
Example:
For key 0, compare its values with next key value which is 3.
3 compare with [1,2,4,8,16] and replace 1,2 with 3 because 3 > 1 and 2
For key 3, compare its values with next key value which is 7.
7 compare with [4,5,7,11,19] and replace 4,5 with 7 because 7 > 4 and 5
The code written below does the following:
For the first set of values [1,2,4,8,16]
1 compare with [0]
2 compare with [0]
4 compare with [0]
etc.. and it moves on to another set of values
[4,5,7,11, 19]
4 compare with [3]
5 compare with [3]
7 compare with [3]
How can I amend the code to achieve the desired outcome mentioned above?
public void updateFingerTable() {
chordSize = chord.initChordSize;
for (Map.Entry<Integer, node> m : peerList.entrySet()) {
for (int i=0; i<chordSize; i++) {
System.out.println("Successor i: " + m.getValue().successor[i]);
System.out.println ("Key: " + m.getKey());
if (m.getValue().successor[i] < m.getKey()) {
m.getValue().successor[i] = m.getKey();
//System.out.println(m.getValue().successor[i]);
}
}

First of all, you seem to make the (wrong!) assumption that a HashMap is ordered.
This is not the case!
If you want a map that is ordered by the value of its keys, then you have to use a TreeMap. (Alternatively, you could collect all entries from the map, and put them into a list, which you then could sort based on their key).
Apart from that, determining a "next" key in a map is not so simple. (In fact, for a TreeMap, you could use the higherKey method, but this should not be necessary here).
You can simply walk though the entries, and always refer to the previous entry for which you update the list (based on the key of the current entry).
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
public class KeyValueListTest
{
public static void main(String[] args)
{
Map<Integer, IntArrayNode> map = new TreeMap<Integer, IntArrayNode>();
map.put(0, new IntArrayNode(new int[]{1,2,4,8,16}));
map.put(3, new IntArrayNode(new int[]{4,5,7,11,19}));
map.put(7, new IntArrayNode(new int[]{8,9,11,15,23}));
System.out.println("Before update:");
for (Map.Entry<Integer, IntArrayNode> e : map.entrySet())
{
System.out.println(e);
}
update(map);
System.out.println("After update:");
for (Map.Entry<Integer, IntArrayNode> e : map.entrySet())
{
System.out.println(e);
}
}
private static void update(IntArrayNode node, int minValue)
{
for (int i=0; i<node.getNumElements(); i++)
{
node.setElement(i, Math.max(minValue, node.getElement(i)));
}
}
public static void update(Map<Integer, IntArrayNode> map)
{
Map.Entry<Integer, IntArrayNode> previous = null;
for (Map.Entry<Integer, IntArrayNode> e : map.entrySet())
{
if (previous != null)
{
update(previous.getValue(), e.getKey());
}
previous = e;
}
}
}
class IntArrayNode
{
private final int elements[];
IntArrayNode(int elements[])
{
this.elements = elements.clone();
}
int getNumElements()
{
return elements.length;
}
int getElement(int index)
{
return elements[index];
}
void setElement(int index, int value)
{
elements[index] = value;
}
#Override
public String toString()
{
return Arrays.toString(elements);
}
}
For your example input, this will print
Before update:
0=[1, 2, 4, 8, 16]
3=[4, 5, 7, 11, 19]
7=[8, 9, 11, 15, 23]
After update:
0=[3, 3, 4, 8, 16]
3=[7, 7, 7, 11, 19]
7=[8, 9, 11, 15, 23]

you can consider value as dynamic array of Integer that can be implemented using ArrayList and key as Integer.You can code like this for your purpose:
List<Integer> value=new ArrayList<>();
for (Map.Entry pair : map.entrySet())
{
Integer key=(Integer)pair.getKey();
for(Integer x:(ArrayList<Integer>)(pair.getValue()))
{
if(key>x)
{
value.add(key);
}
else
{
value.add(x);
}
}
map.put(key, (ArrayList<Integer>) value);
System.out.println(value);
value=new ArrayList<>();
}

I see two issues from first glance that seems to violate the logic of your examples.
According to your examples, map values of current element must be compared to map key of next element, not current.
First, line with for (int i=0; i<chordSize; i++) {: I was expecting that you would loop over m.getValue().length() so you can iterate values that are associated with m, not with chordSize which seems to be involved with this Map, though I’m not sure why.
Second, line with if (m.getValue().successor[i] < m.getKey()) { I think you’ll need to compare m.getValue().successor[i] with next element’s key, not current element’s key.
Having that in mind, you'll need to put all map items into another data structure that provides you with index based access (array seems OK, cause you already know the size of the map) to its components so you'll be able to get next map item while also working with current one. That will make comparing a lot more easy.
Hope that helps.

I fear your example is still a bit unclear. Is the following what you want to do:
3 keys [0,3,7]
Three sets of values: [1,2,4,8,16], [4,5,7,11,19], [8,9,11,15,23]
Step 1):
You take the 0 from the keys and compare it with the values:
0 > 1? No ... 0>16? No.
Step 2):
Compare the 3 from the keys with the values:
3>1? Yes -> Replace 1 with 3 ... 3>16? No ...
Step 3):
Compare the 7 from the keys with the values:
7>1 Yes -> Replace 1 with 7, 7>2? Yes -> Replace...
If yes, why bother to compare the smaller keys? The key 7 will "override" all changes that 0 and 3 have done before, so simply find the biggest key and compare it with the values.
int keyArray[] = new int[]{0,3,7};
int largest = keyArray[0];
for(int i=1; i< keyArray.length; i++)
{
if(keyArray[i] > largest)
largest = keyArray[i];
}
Then you could go over your valuesets and compare them with largest.equals() to the HashMap.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<Integer, List<Integer>> hash = new HashMap<Integer,List<Integer>>();
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);list1.add(2);list1.add(4);list1.add(8);list1.add(16);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(4);list2.add(5);list2.add(7);list2.add(11);list2.add(19);
List<Integer> list3 = new ArrayList<Integer>();
list3.add(8);list3.add(9);list3.add(11);list3.add(15);list3.add(23);
hash.put(0,list1);
hash.put(3,list2);
hash.put(7,list3);
System.out.println("Input:");
for (Map.Entry<Integer, List<Integer>> m1 : hash.entrySet()) {
System.out.println("Successor i: " + m1.getValue());
System.out.println ("Key: " + m1.getKey());
}
Map<Integer, List<Integer>> out = hash;
List<Integer> list = new ArrayList<Integer>();
int keyValue = 0;
int count=0;
for (Entry<Integer, List<Integer>> m : hash.entrySet()) {
if(count==0){
list = m.getValue();
keyValue = m.getKey();
count++;
continue;
}
else{
for(int i=0;i<list.size();i++){
if(m.getKey()>list.get(i)){
list.set(i, m.getKey());
}
}
out.put(keyValue,list);
list = m.getValue();
keyValue = m.getKey();
}
}
System.out.println("Output:----------------");
for (Map.Entry<Integer, List<Integer>> m1 : out.entrySet()) {
System.out.println("Successor i: " + m1.getValue());
System.out.println ("Key: " + m1.getKey());
}
}
}

Related

How to print the sum of values from the same objects of 2 parameter in array

I am learning java and I hit into a snag as I could not figure out my loop or array.
I have an array which contains class objects containing a string and integer parameters, in my code, it will be name and dollars.
I am trying to print out the array in which, if there is a same name, it is to print once and with the sum of the dollars (from the same name).
In my Dollars.java
public class Dollars
{
private String name;
private int dollars;
public dollars (String name, int dollars)
{
this.name = name;
this.dollars = dollars;
}
public String getName()
{
return name;
}
public int getChange()
{
return dollars;
}
}
In my main file/ TestDollars.java
public class TestDollars
{
public static void displayArray(Dollars[] dol)
{
int sum = 0;
for (int n=0; n<dol.length; n++)
{
for (int m=n+1; m<dol.length; m++)
{
if (dol[n].getName().equals(dol[m].getName()))
{
// System.out.printf("%s -- %d\n", dol[n].getName(), dol[n].getChange());
sum = dol[n].getChange() + dol[m].getChange();
System.out.printf("%s -- %d\n", dol[m].getName(), sum);
break;
}
}
System.out.printf("%s -- %d\n", dol[n].getName(), dol[n].getChange());
}
}
public static void main(String[] args)
{
// Test with 5 records
Dollars[] dollarsArr = new Dollars[5];
dollarsArr[0] = new Dollars("john", 10);
dollarsArr[1] = new Dollars("peter", 12);
dollarsArr[2] = new Dollars("sam", 5);
dollarsArr[3] = new Dollars("alvin", 16);
dollarsArr[4] = new Dollars("peter", 30);
displayArray(dollarsArr);
}
}
Irregardless where I place my print statement in the displayArray, the record 'peter' will gets printed twice.
Expected output:
john -- 10
peter -- 42
sam -- 5
alvin -- 16
Current output:
john -- 10
peter -- 42
peter -- 12
sam -- 5
alvin -- 16
peter -- 30
You want to group your list by name, please use JAVA 8+ API Stream and the collector group by
public static void displayArray(Dollars[] dol)
{
Stream.of(dol)
// Group by name
.collect(Collectors.groupingBy(Dollars::getName))
.entrySet().stream()
// Collect a map name and calculate the sum
.collect(
Collectors.toMap(x -> {
int total= x.getValue().stream().mapToInt(Dollars::getChange).sum();
return new Dollars(x.getKey(),total);
}, Map.Entry::getValue))
// Print
.forEach((dollarsTotal, vals) -> {
System.out.println(dollarsTotal.getName()+ " -- "+ dollarsTotal.getChange());
// Bonus : Display transactions :
for(Dollars transaction : vals)
{
System.out.println(" \t "+transaction.getName() + " add -- " + transaction.getChange());
}
});
}
If you want only the values you can collect the keyset
Set<Dollars> groupedByName = Stream.of(dol)
// Group by name
.collect(Collectors.groupingBy(Dollars::getName))
.entrySet().stream()
// Collect a map name and calculate the sum
.collect(
Collectors.toMap(x -> {
int total= x.getValue().stream().mapToInt(Dollars::getChange).sum();
return new Dollars(x.getKey(),total);
}, Map.Entry::getValue)).keySet();
The other answer guides you on fixing your code (Buy they require more work to avoid double counting).
You can reduce the time complexity from O(n2) to O(n) (and make it simpler) by having a data structure (like a map) to aggregate the result.
Let us create a Map<String, Integer> to map a name to the total dollars for that name.
Map<String, Integer> result = new HashMap<>();
for (int i = 0; i < dol.length; i++) {
if (!result.containsKey(dol[i].getName())) { //first time you encounter a name
result.put(dol[i].getName(), dol[i].getChange());
} else {
//add the current change to the already existing sum
int sumSoFar= result.get(dol[i].getName());
result.put(dol[i].getName(), sumSoFar + dol[i].getChange());
}
}
System.out.println(result);
Result is,
{peter=42, alvin=16, john=10, sam=5}
You can simplify the above code using Map's merge method as:
for (Dollars dollars : dol) {
result.merge(dollars.getName(), dollars.getChange(), Integer::sum);
}
The third argument is a BiFunction which sums up the old value and new value (the sum accumulated so far and the current change value). When written as a lambda expression, Integer::sum can be written as (sumSoFar, currentChange) -> sumSoFar + currentChange.
A stream evangelist way would be to use Collectors.groupingBy and Collectors.summingInt.
Arrays.stream(dol)
.collect(Collectors.groupingBy(Dollars::getName, Collectors.summingInt(Dollars::getChange)));
While navigating the array, assign the change of each non-null array-element to a variable e.g. sum and then add the change of the succeeding duplicate elements to it. Make sure to assign null to the indices where duplicate elements are found so that they can not be counted again. It also means that you will have to perform a null check before performing any operation on the array elements. Print the value of sum once you have checked the complete array for duplicate elements.
public static void displayArray(Dollars[] dol) {
for (int n = 0; n < dol.length; n++) {
if (dol[n] != null) {
int sum = dol[n].getChange();
for (int m = n + 1; m < dol.length; m++) {
if (dol[m] != null && dol[n].getName().equals(dol[m].getName())) {
sum += dol[m].getChange();
dol[m] = null;
}
}
System.out.printf("%s -- %d\n", dol[n].getName(), sum);
}
}
}
Output:
john -- 10
peter -- 42
sam -- 5
alvin -- 16
Note: If you want to keep the original array intact, pass the clone of the array to the method, displayArray instead of passing the array itself as shown below:
displayArray(dollarsArr.clone());

How would you update the values in a hashmap based on prior conditions?

Something fundamental about hashmaps and for loops is hard for me to grasp here. What I'm trying to do is add +1 to the value associated with the key based on the Keys method every time the value within the array list is associated with the key string.
So if there are 3 values in the array list that are positive then the hashmap should have the value with the key "positive" updated to 3.
Any help/advice would be appreciated - thank you.
public String Keys(double input){
if (input > 0){
System.out.println("positive");
}
else if (input < 0) {
System.out.println("negative");
}
else if (input == 0) {
System.out.println("zero");
}
return "";
}
public HashMap<String, Integer> increaseValues(ArrayList<Double> inputs){
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("positive", 0);
hashMap.put("negative", 0);
hashMap.put("zero", 0);
//What I tried before adding the Keys method.
//This updates the value but the loop won't continue if another input in the
//arraylist is true.
for (int i = 0; i < inputs.size(); i++){
double input = inputs.get(i);
if (input > 0){
hashMap.put("positive", 1);
} else if (input < 0){
hashMap.put("negative", 1);
} else if (input == 0){
hashMap.put("zero", 1); }
return hashMap;
}
public void main(String[] args){
ArrayList<Double> inputs = new ArrayList<>();
inputs.add(-4.56);
inputs.add(-4.66);
inputs.add(0.0);
inputs.add(6.0);
inputs.add(-6.99);
inputs.add(6.97);
}
Map.put(k, v) always overrides your previous value. You can use the "traditional approach":
if (!map.containsKey("positive"))
map.put("positive", 0);
map.put("positive", map.get("positive") + 1);
or better use the new merge funtction that is added for exactly such cases:
map.merge("positive", 1, (prev, one) -> prev + one);
But this whole logic can be greatly shortened by using Math.signum() and stream collectors:
Map<Double, Long> collect = inputs.stream()
.collect(Collectors.groupingBy(Math::signum,
Collectors.counting()));
System.out.println("positive: " + collect.get(1.0));
System.out.println("negative: " + collect.get(-1.0));
System.out.println("zero: " + collect.get(0.0));
Lets start with a quick tidy, lets create an enum and remove those nasty String constants that you don't have defined anywhere:
public enum Sign {
POSITIVE,
ZERO,
NEGATIVE;
public static Sign of(double d) {
if (d > 0) {
return POSITIVE;
}
if (d < 0) {
return NEGATIVE;
}
return ZERO;
}
}
Now we can trivially write a method to increment the appropriate value:
public void increment(final double d, final Map<Sign, Integer> count) {
count.merge(Sign.of(d), 1, Integer::sum);
}
For a quick test:
final Map<Sign, Integer> count = new EnumMap<>(Sign.class);
increment(0, count);
System.out.println(count);
increment(-1, count);
System.out.println(count);
increment(1, count);
System.out.println(count);
increment(-2, count);
System.out.println(count);
increment(2, count);
System.out.println(count);
Output:
{ZERO=1}
{NEGATIVE=1, ZERO=1}
{POSITIVE=1, NEGATIVE=1, ZERO=1}
{POSITIVE=1, NEGATIVE=2, ZERO=1}
{POSITIVE=2, NEGATIVE=2, ZERO=1}
So how does this magic work? From the documentation for Map.merge
If the specified key is not already associated with a value or is
associated with null, associates it with the given non-null value.
Otherwise, replaces the associated value with the results of the given
remapping function, or removes if the result is null. This method may
be of use when combining multiple mapped values for a key.
So it takes the key as the first argument to merge - in the case Sign.of(d); this selects the correct bucket. If the value mapped to that key is null then it simply puts a mapping for the key to the value passed as the second argument - in this case 1. Otherwise it gets a litte more complicated; it takes the value currently mapped to that key and uses the remappingFunction passed as the third argument. This is a BiFunction<V,V,V>, so it takes two arguments of type V, the value type and returns a single one - it merges the two together. Here we use Integer::sum to take the existing value, the new value and return their sum.
But we can go one step further, we can use a Stream to carry this out on an arbitrary double[]:
public Map<Sign, Long> count(final double[] d) {
return Arrays.stream(d)
.mapToObj(Sign::of)
.collect(groupingBy(identity(), () -> new EnumMap<>(Sign.class), counting()));
}
Note: I've used an EnumMap here, which is Map optimised for using an enum as the key.
You can solve it pretty concisely with streams. You need a function which turns value into the negative/zero/positive key. Then just group by this key with a counting collector. It's basically a two-liner:
List<Double> values = Arrays.asList(-4.56,-4.66,0.0, 6.0, -6.99, 6.97);
Function<Double, String> toKey = v -> v < 0 ? "negative" : (v == 0 ? "zero" : "positive");
Map<String, Long> result = values
.stream()
.collect(Collectors
.groupingBy(
toKey,
Collectors.counting()));
The method put of HashMap maps unique keys with values. It replaces the existing value with the new value in case the provided key is already present in the map.
You need to define a method similar to below.
public void addValueToList(Double d, List<Double> inputs , Map<String,Integer> map){
if( d == null ) return;
if ( isZero(d) ){
Integer count = map.get("zero");
if(count == null){
count = 1;
}else {
count ++;
}
map.put("zero",count);
}else if( isNegative(d) ) {
Integer count = map.get("negative");
if(count == null){
count = 1;
}else {
count ++;
}
map.put("negative",count);
}else {
Integer count = map.get("positive");
if(count == null){
count = 1;
}else {
count ++;
}
map.put("positive",count);
}
inputs.add(d);
}
For writing method for comparing the value you can refer https://stackoverflow.com/a/10400718/504133

Combination From Rows

I want to check the combination of values from data its exist or not. Below code works fine buts its looks inefficient. I am looking for some good solution of this problem.
public static void main(String args[]) {
Integer data[] = {
1, 2, 5, 1, 9, 3, 5, 3, 2
};
Integer combination[] = {
1, 3 ,2
};
System.out.println("Result: " + combinations(data, combination));
}
public static boolean combinations(Integer dataset[], Integer combination[]) {
boolean results[] = new boolean[combination.length];
Integer count = 0;
for (Integer comb : combination) {
for (Integer data : dataset) {
if (data.equals(comb)) {
results[count++] = true;
break;
}
}
}
for (Boolean result : results) {
if (!result) {
return false;
}
}
return true;
}
strong text
Looks like you just want to check if the combination is a subset of your data set...The order in which it appears in your data set is not important. Is that correct?
How big will be your data set? Is the data set created whenever it is required or is it maintained throughout?
If data set is large and is maintained throughout, it would be easier to search if you can maintain it sorted.
for (Integer comb : combination) {
if (Arrays.binarySearch(dataset, comb) < 0)
return false; //If any element is not found, return false
}
}
return true;
If you can keep the combination also sorted, you can further optimize it.
int loc = 0;
for (Integer comb : combination) {
loc = Arrays.binarySearch(dataset, loc, data.length, comb);
//Since both are sorted, u can be sure that next element will be
//after previous element match
if (loc < 0)
return false;
}
}
return true;
Even if you can't maintain a sorted array, one optimization u can do is to get rid of that boolean array and the for-loop at the bottom. Algorithm is as follows...
boolean isMatch = false;
for (Integer comb : combination) {
//We will be here in two condition -
// 1. first iteration or previous element was found in dataset.
// 2. Just set to false to check next element. Reset the flag
boolean isMatch = false;
for (Integer data : dataset) {
if (data.equals(comb)) {
//match found for the current combination element
isMatch = true;
break;
}
}
//This mean one of the combination element is not there. Break out.
if (!isMatch) break;
}
return isMatch;
Sort the dataset set which is complexity nlog(n). (Quick or merge sort maybe ? ) Then run binary search for every member of combination array over dataset. Binary search complexity log(n). When you do this for every member of combination array complexity will be nlog(n).
nlog(n) + nlog(n) = 2nlog(n) which is O(nlogn). This way your performance will be increase.
Code
public static boolean combinations(Integer dataset[], Integer combination[]) {
sort(dataset); // quick or insertion sort, nlogn
for (Integer comb : combination) { // n
if (!binarysearch(dataset, comb)) //logn
return false;
} //n*logn = nlogn
return true;} //2nlogn = O(nlogn)
You can change from array to ArrayList and use the containsAll method. not sure if it is efficient enough but will make your code shorter.
public static void main(String args[]) {
Integer data[] = {1, 2, 5, 1, 9, 3, 5, 3, 2};
Integer combination[] = {1,3 ,2};
System.out.println("Result: " + combinations(data, combination));
}
public static boolean combinations(Integer dataset[], Integer combination[]) {
List<Integer> data = Arrays.asList(dataset);
List<Integer> comb = Arrays.asList(combination);
return data.containsAll(comb);
}
Since your data consists of Integers which implements "Comparable", I would suggest you exploit that and construct a TreeSet and add all the data into it. You can then run a contains() to find if an element is present in the TreeSet or not.
TreeSet guarantees log(n) cost for each add, delete and contains.
Adding all elements(n) will cost you nlog(n).
Finding if 'm' elements are present will cost you mlog(n).

Incrementing different variables on different conditions

I have multiple int type variables and on specific condition any one of those variables got incremented. Now I have to know some data structure in java that i can do this thing without using multiple variables.
A portion of my code is here:
switch(diff)
{
case 4:
{
count4++;
break;
}
case 5:
{
count5++;
break;
}
case 6:
{
count6++;
break;
}
}
Conditions may be increased so it is not good approach to add variable for each new condition. Kindly let me know some other better approach or data structure which can solve my problem.
Edit 1:
I am extracting time difference between consucetive lines in log file. Actually in the end I need a summary like
Difference 3 sec = 10
Difference 4 sec = 5
For above purpose I am using counter variables for each time difference. I need to know about some other way to do this thing,
You could use a Map (e.g. HashMap) with the key representing the name of the variable and the map's value representing the variable's value. This allows for having a flexible data structure where it is not necessary to know in before how many "variables" there will be.
This is strange because of the names you gave to your variables, but you could use an array:
int[] counts = {0, 0, 0};
Then count4 is counts[0], count5 is counts[1] and count6 is counts[2] so you can do:
counts[diff - 4]++;
You can use a HashMap
Example:
public class Test
{
public static void main(String[] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("counter5", 1);
map.put("counter4", 1);
map.put("counter2", 1);
map.put("counter1", 1);
int diff = 2;
compute(map, diff);
diff = 2;
compute(map, diff);
diff = 1;
compute(map, diff);
}
private static void compute(HashMap<String, Integer> map, int diff)
{
System.out.println("Before counter no: "+diff+" value "+map.get("counter" + diff));
Integer counter = map.get("counter" + diff);
map.put("counter" + diff, --counter);
System.out.println("After counter no: "+diff+" value "+map.get("counter" + diff));
System.out.println("");
}
}
As pzaenger you can do something like:
As you already know how many case are there so you can initialize an array with that much size. Like you have 10 case then you can initialize an int array of size 10 as:
int[] count = new int[10];
now suppose you have a case of 4, i.e. 4th index of int array but as index start from 0 so you can do
int[4-1] = int[4-1]++;
if you just want to keep track of the diff number you could do something like this.
Map<Integer, Integer> pathMap = new HashMap<Integer, Integer>();
public void testSaveEntries() {
for ( int i = 0; i < 10; i++) {
int value = i % 5;
increaseCounter(value);
}
}
private void increaseCounter(int i) {
Integer value = pathMap.get(i);
pathMap.put(i, value == null ? 1 : ++value);
}
Try This....
public static void main(String[] args) {
int[] aaa=new int[]{10,2,4,5,7,8,3,34,4,4,545,5,3,4,4,5,5,5,10,3,4,45,6,2,7};
Map<Integer, Integer> all_counts=new LinkedHashMap<Integer,Integer>();
for (int key : aaa) {
if(all_counts.containsKey(key))
{
Integer count=all_counts.get(key);
count++;
all_counts.put(key, count);
}
else
{
all_counts.put(key, 1);
}
}
for (Map.Entry<Integer, Integer> entry : all_counts.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}

how to get the most frequent items

I am working on an application which has a large array containing lines of numbers,
transNum[20000][200]//this is the 2d array containing the numbers and always keep track of the line numbers
I am using a nested loop to look for the most frequent items. which is
for(int i=0/*,lineitems=0*/;i<lineCounter;i++)
{
for(int j=0,shows=1;j<lineitem1[i];j++)
{
for(int t=i+1;t<lineCounter;t++)
{
for(int s=0;s<lineitem1[t];s++)
{
if(transNum[i][j]==transNum[t][s])
shows++;
}
}
if(shows/lineCounter>=0.2)
{
freItem[i][lineitem2[i]]=transNum[i][j];
lineitem2[i]++;
}
}
}
when I was doing tests using small input arrays like test[200][200], this loop works fine and the computing time is acceptable, but when I try to process the array contains 12000 lines, the computing time is too long, so I am thinking if there are other ways to compute the frequent items rather than using this loop.I just ran a test on 10688 lines, and the time to get all the frequent item is 825805ms, which is way to expensive.
Bear in mind this is an O(n^2) algorithm at best and could be worse. That means the number of operations is proportional to the count of the items squared. After a certain number of lines, performance will degrade rapidly and there's nothing you can do about it except to improve the algorithm.
Depends on your input. If you are also inserting the data in the same code then you can count frequent items as you insert them.
Here is a pseudo-C solution:
int counts[1000000];
while(each number as n)
{
counts[n]++;
// then insert number into array
}
EDIT #2: Make sure, so you don't get unexpected results, to initialize all the items in the array to zero.
The Multiset implementation from Google Guava project might be useful in such cases. You could store items there and then retrieve set of values with count of each occurrence.
Gave the algorithm for this one some thought. Here's the solution I came up with:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class NumberTotalizerTest {
public static void main(String args[]) {
HashMap<Integer,Integer> hashMap = new HashMap<Integer,Integer>();
// Number input
Random randomGenerator = new Random();
for (int i = 1; i <= 50; ++i ) {
int randomInt = randomGenerator.nextInt(15);
System.out.println("Generated : " + randomInt);
Integer tempInt = hashMap.get(randomInt);
// Counting takes place here
hashMap.put(randomInt, tempInt==null?1:(tempInt+1) );
}
// Sorting and display
Iterator itr = sortByValue(hashMap).iterator();
System.out.println( "Occurences from lowest to highest:" );
while(itr.hasNext()){
int key = (Integer) itr.next();
System.out.println( "Number: " + key + ", occurences: " + hashMap.get(key));
}
}
public static List sortByValue(final Map m) {
List keys = new ArrayList();
keys.addAll(m.keySet());
Collections.sort(keys, new Comparator() {
public int compare(Object o1, Object o2) {
Object v1 = m.get(o1);
Object v2 = m.get(o2);
if (v1 == null) {
return (v2 == null) ? 0 : 1;
}
else if (v1 instanceof Comparable) {
return ((Comparable) v1).compareTo(v2);
}
else {
return 0;
}
}
});
return keys;
}
}

Categories

Resources