HashMap "Unique" Keys - java

Firstly, I'd like to say I am still learning java, so excuse any unconventional code and/or questions.
I'm trying to allow the HashMap to set 'unique' keys while only using one put method.
This is what I currently have:
static int killcount = 0;
static Map<Integer, Integer> enumMap = new HashMap<Integer, Integer>();
public static void incrementKillcount() {
enumMap.put(getId(), killcount++);
}
(Again, excuse any unconventional java code, I'm still learning).
In this instance, if I'm not mistaken, the key is interchangeable (or at least from my experimenting). So the key doesn't really matter all that much. But while only having one put method, every key shares the same value. I'd like to make the value have some sort of 'unique' value.
For example, if I wanted this to count by increasing the killcount by 1 (killcount++;) until it reached 10, and then moving to a different key to count to 10 again, it would start counting from 10 instead of 1.
Thanks in advance, and again, excuse me for my terrible java skills! :)

The problem is static key word for killcount in your:-
static int killcount = 0;
The killcount will be initialized only once since it is static.
So increment operator will increment the previous value in killcount.
Solution to your problem
:-
set the killcount to zero while changing the key after saving it to map i.e. once killcount reaches 10.
public static void incrementKillcount() {
enumMap.put(getId(), killcount++);
if(killcount==10){
//resetting the static killcount value once it reaches 10
killcount=0;
}
For Scenario in your comment:-
public static void main(String[] args){
int sizeOfEachJar=10;
int numberOfJars=2;
Map<Integer, Integer> jarMap=new HashMap<Integer, Integer>(sizeOfEachJar);
//I am putting 10 cookies in each jar which is max size of each jar
for(int i=1;i<=numberOfJars;i++){
jarMap.put(i, sizeOfEachJar);
}
//Now eating three cookies from first jar
for(int i=0;i<3;i++){
jarMap.put(1, sizeOfEachJar--);
}
//Now eating 2 cookies out of 2nd jar
for(int i=0;i<2;i++){
jarMap.put(2, sizeOfEachJar--);
}
//Now finding out how many cookies remaining in all jars
int remainingCookies=0;
for(int i=1;i<=numberOfJars;i++){
remainingCookies+=jarMap.get(i);
}
System.out.println(remainingCookies);
}

You have to check your getID() code whether it returns same value or not.

as per your words your getId is returning same value each time
assuming same =1
int getId()
{
return same;
}
update your code with getId() by placing some use full logic to return a key
you may update like:
int getId()
{
return same++;
}
you may take same as static or according to your convince.
prefer effective java for the same.

Related

Multiple string replacement in a single string generating all possible combinations

I'm trying to replace multiple words in a string with multiple other words. The string is
I have sample {url} with time to {live}
Here the possible values for {url} are
point1
point2
Possible values for {live} are
10
20
The four possible answers are
I have sample point1 with time to 10
I have sample point1 with time to 20
I have sample point2 with time to 10
I have sample point2 with time to 20
This can also increase to three.
I have {sample} {url} with time to {live}
What would be best data structures and good approach to solve this problem ?
You can do it something like:
public static void main(String[] args) {
String inputStr = "I have {sample} {url} with time to {live}";
Map<String, List<String>> replacers = new HashMap<String, List<String>>(){{
put("{sample}", Arrays.asList("point1", "point2"));
put("{live}", Arrays.asList("10", "20"));
put("{url}", Arrays.asList("url1", "url2", "url3"));
}};
for (String variant : stringGenerator(inputStr, replacers)) {
System.out.println(variant);
}
}
public static List<String> stringGenerator(String template, Map<String, List<String>> replacers) {
List<String> out = Arrays.asList(template);
for (Map.Entry<String, List<String>> replacerEntry : replacers.entrySet()) {
List<String> tempOut = new ArrayList<>(out.size()*replacerEntry.getValue().size());
for (String replacerValue : replacerEntry.getValue()) {
for (String variant : out) {
tempOut.add(variant.replace(replacerEntry.getKey(), replacerValue));
}
}
out = tempOut;
}
return out;
}
also you can try make similar solution with recursion
You can use a template string and print the combinations using System.out.format method like below:
public class Combinations {
public static void main(String[] args) {
String template = "I have sample %s with time to %d%n"; //<-- 2 arguments case
String[] points = {"point1", "point2"};
int[] lives = {10, 20};
for (String point : points) {
for (int live : lives) {
System.out.format(template, point, live);
}
}
}
}
The code solves the 2 argument case but it can be easily extended to the 3 cases substituting the sample word with another %s in the template and a triple loop.
I'm using the simplest array structures, it is up to you decide which structure is the more adapt for your code.
Unless you want the hardcoded solution with simple nested loops shown in Dariosicily's answer, you will need to store "replacee-replacements" pairings, for example the string {url} paired with a list of strings point1 and point2. A simple class can do that, like
class StringListPair{
public final String s;
public final List<String> l;
public StringListPair(String s,List<String> l){
this.s=s;
this.l=l;
}
}
and then a list of replacements can be initialized as
List<StringListPair> mappings=Arrays.asList(
new StringListPair("{url}",Arrays.asList("point1","point2")),
new StringListPair("{live}",Arrays.asList("10","20","30")));
(If someone wants to totally avoid having a helper class, these are all strings, so a List<List<String>> can do the job too, having "{url}","point1","point2" lists inside, just then we would have to fight with indexing the inner lists everywhere)
Then two common approaches pop into my mind: a recursive one, generating all possible combinations in a single run, and a direct-indexing one, numbering all combinations and generating any of them directly upon request. Recursion is simpler to come up with, and it has no significant drawbacks if all the combinations are needed anyway. The direct approach generates a single combination at a time, so if many combinations are not going to be used, it can spare a lot of memory and runtime (for example if someone would need a single randomly selected combination only, out of millions perhaps).
Recursion will be, well, recursive, having a completed combination generated in its deepest level, thus it needs the following:
the list of combinations (because it will be extended deep inside the call-chain)
the mappings
the candidate it is working on at the moment
something to track what label it is supposed to replace a the moment.
Then two things remain: recursion has to stop (when no further labels remain for replacement in the current candidate, it is added to the list), or it has to replace the current label with something, and proceed to the next level.
In code it can look like this:
static void recursive(List<String> result,List<StringListPair> mappings,String sofar,int partindex) {
if(partindex>=mappings.size()) {
result.add(sofar);
return;
}
StringListPair p=mappings.get(partindex);
for(String item:p.l)
recursive(result,mappings,sofar.replace(p.s,item),partindex+1);
}
level is tracked by a simple number, partindex, current candidate is called sofar (from "so far"). When the index is not referring to an existing element in mappings, the candidate is complete. Otherwise it loops through the "current" mapping, and calling itself with every replacement, well, recursively.
Wrapper function to creata and return an actual list:
static List<String> userecursive(List<StringListPair> mappings,String base){
List<String> result=new ArrayList<>();
recursive(result, mappings, base, 0);
return result;
}
The direct-indexing variant uses some maths. We have 2*3 combinations in the example, numbered from 0...5. If we say that these numbers are built from i=0..1 and j=0..2, the expression for that could be index=i+j*2. This can be reversed using modulo and division operations, like for the last index index=5: i=5%2=1, j=5//2=2. Where % is the modulo operator, and // is integer division. The method works higher "dimensions" too, just then it would apply modulo at every step, and update index itself with the division as the actual code does:
static String direct(List<StringListPair> mappings,String base,int index) {
for(StringListPair p:mappings) {
base=base.replace(p.s,p.l.get(index % p.l.size())); // modulo "trick" for current label
index /= p.l.size(); // integer division throws away processed label
}
return base;
}
Wrapper function (it has a loop to calculate "2*3" at the beginning, and collects combinations in a list):
static List<String> usedirect(List<StringListPair> mappings,String base){
int total=1;
for(StringListPair p:mappings)
total*=p.l.size();
List<String> result=new ArrayList<>();
for(int i=0;i<total;i++)
result.add(direct(mappings,base,i));
return result;
}
Complete code and demo is on Ideone

Delete items from hashtable (java)

I have a class Section with several methods including methods get_key() and get_angle(). Items of type Section are added to a hashtable implemented in class Hashtable.
According to my task I should delete such elements from the hashtable which have bigger value of function get_angle() than given_value.
class Hashtable{
private Section[] hash_array; //array of cells of the hashtable
public int size;
public void remove_given(double given_value)
{
for(int i = 0; i < size; i++)
{
if (hash_array[i] != null)
{
double value = hash_array[i].get_angle(); //value of needed function to compare
if (value > given_value)
{
int key_ = hash_array[i].get_key(); //get key for the item in order to delete it
Delete(key_); //delete item
}
}
}
}
}
But the method doesn`t delete any elements. I checked the method Delete() separately and it works just fine as well as other methods called on this method . I really need to figure it out. So I will be grateful for your help.
Debug your code, does it enter the for-loop. How do you initialize the value of size variable? If you forget to initialize it by default it will be zero. It is better to get the size from the hash_array.length.
For one thing you're using the uninitialized global var, size, the size used in the for loop needs to be the size of the Hash collection. Also how is the Hash initialized? Does it contain what you think? I'd follow the aforementioned suggestion to step through the code with a debugger, perhaps the keys aren't what you think they are...

Collectors.summingLong or mapToLong to summarize long values

I've got a list of objects with a value and want to summarise all these values. What is the preferred way to do this in Java 8?
public static void main(String[] args) {
List<AnObject> longs = new ArrayList<AnObject>();
longs.add(new AnObject());
longs.add(new AnObject());
longs.add(new AnObject());
long mappedSum = longs.stream().mapToLong(AnObject::getVal).sum();
long collectedSum = longs.stream().collect(Collectors.summingLong(AnObject::getVal));
System.out.println(mappedSum);
System.out.println(collectedSum);
}
private static class AnObject {
private long val = 10;
public long getVal() {
return val;
}
}
I think mapToLong is more straight forward but I can't really motivate why.
Edit: I've updated the question by changing from summarizeLong to summingLong, that's why some answers and comments might seem a bit off.
I think using Collectors.summarizingLong(AnObject::getVal)) would do more work than you need it to do, as it computes other statistics beside the sum (average, count, min, max, ...).
If you just need the sum, use the simpler and more efficient method :
long mappedSum = longs.stream().mapToLong(AnObject::getVal).sum();
After you changed Collectors.summarizingLong to Collectors.summingLong, it's hard to say which option would be more efficient. The first option has an extra step (mapToLong), but I'm not sure how much difference that would make, since the second option does more work in collect compared to what the first option does in sum.

Hashmap vs Array performance

Is it (performance-wise) better to use Arrays or HashMaps when the indexes of the Array are known? Keep in mind that the 'objects array/map' in the example is just an example, in my real project it is generated by another class so I cant use individual variables.
ArrayExample:
SomeObject[] objects = new SomeObject[2];
objects[0] = new SomeObject("Obj1");
objects[1] = new SomeObject("Obj2");
void doSomethingToObject(String Identifier){
SomeObject object;
if(Identifier.equals("Obj1")){
object=objects[0];
}else if(){
object=objects[1];
}
//do stuff
}
HashMapExample:
HashMap objects = HashMap();
objects.put("Obj1",new SomeObject());
objects.put("Obj2",new SomeObject());
void doSomethingToObject(String Identifier){
SomeObject object = (SomeObject) objects.get(Identifier);
//do stuff
}
The HashMap one looks much much better but I really need performance on this so that has priority.
EDIT: Well Array's it is then, suggestions are still welcome
EDIT: I forgot to mention, the size of the Array/HashMap is always the same (6)
EDIT: It appears that HashMaps are faster
Array: 128ms
Hash: 103ms
When using less cycles the HashMaps was even twice as fast
test code:
import java.util.HashMap;
import java.util.Random;
public class Optimizationsest {
private static Random r = new Random();
private static HashMap<String,SomeObject> hm = new HashMap<String,SomeObject>();
private static SomeObject[] o = new SomeObject[6];
private static String[] Indentifiers = {"Obj1","Obj2","Obj3","Obj4","Obj5","Obj6"};
private static int t = 1000000;
public static void main(String[] args){
CreateHash();
CreateArray();
long loopTime = ProcessArray();
long hashTime = ProcessHash();
System.out.println("Array: " + loopTime + "ms");
System.out.println("Hash: " + hashTime + "ms");
}
public static void CreateHash(){
for(int i=0; i <= 5; i++){
hm.put("Obj"+(i+1), new SomeObject());
}
}
public static void CreateArray(){
for(int i=0; i <= 5; i++){
o[i]=new SomeObject();
}
}
public static long ProcessArray(){
StopWatch sw = new StopWatch();
sw.start();
for(int i = 1;i<=t;i++){
checkArray(Indentifiers[r.nextInt(6)]);
}
sw.stop();
return sw.getElapsedTime();
}
private static void checkArray(String Identifier) {
SomeObject object;
if(Identifier.equals("Obj1")){
object=o[0];
}else if(Identifier.equals("Obj2")){
object=o[1];
}else if(Identifier.equals("Obj3")){
object=o[2];
}else if(Identifier.equals("Obj4")){
object=o[3];
}else if(Identifier.equals("Obj5")){
object=o[4];
}else if(Identifier.equals("Obj6")){
object=o[5];
}else{
object = new SomeObject();
}
object.kill();
}
public static long ProcessHash(){
StopWatch sw = new StopWatch();
sw.start();
for(int i = 1;i<=t;i++){
checkHash(Indentifiers[r.nextInt(6)]);
}
sw.stop();
return sw.getElapsedTime();
}
private static void checkHash(String Identifier) {
SomeObject object = (SomeObject) hm.get(Identifier);
object.kill();
}
}
HashMap uses an array underneath so it can never be faster than using an array correctly.
Random.nextInt() is many times slower than what you are testing, even using array to test an array is going to bias your results.
The reason your array benchmark is so slow is due to the equals comparisons, not the array access itself.
HashTable is usually much slower than HashMap because it does much the same thing but is also synchronized.
A common problem with micro-benchmarks is the JIT which is very good at removing code which doesn't do anything. If you are not careful you will only be testing whether you have confused the JIT enough that it cannot workout your code doesn't do anything.
This is one of the reason you can write micro-benchmarks which out perform C++ systems. This is because Java is a simpler language and easier to reason about and thus detect code which does nothing useful. This can lead to tests which show that Java does "nothing useful" much faster than C++ ;)
arrays when the indexes are know are faster (HashMap uses an array of linked lists behind the scenes which adds a bit of overhead above the array accesses not to mention the hashing operations that need to be done)
and FYI HashMap<String,SomeObject> objects = HashMap<String,SomeObject>(); makes it so you won't have to cast
For the example shown, HashTable wins, I believe. The problem with the array approach is that it doesn't scale. I imagine you want to have more than two entries in the table, and the condition branch tree in doSomethingToObject will quickly get unwieldly and slow.
Logically, HashMap is definitely a fit in your case. From performance standpoint is also wins since in case of arrays you will need to do number of string comparisons (in your algorithm) while in HashMap you just use a hash code if load factor is not too high. Both array and HashMap will need to be resized if you add many elements, but in case of HashMap you will need to also redistribute elements. In this use case HashMap loses.
Arrays will usually be faster than Collections classes.
PS. You mentioned HashTable in your post. HashTable has even worse performance thatn HashMap. I assume your mention of HashTable was a typo
"The HashTable one looks much much
better "
The example is strange. The key problem is whether your data is dynamic. If it is, you could not write you program that way (as in the array case). In order words, comparing between your array and hash implementation is not fair. The hash implementation works for dynamic data, but the array implementation does not.
If you only have static data (6 fixed objects), array or hash just work as data holder. You could even define static objects.

Why is my counter incrementing in loop, but returns zero?

With my current project, I have to keep a counter of the number of insertions into a TreeMap<String, TreeSet<Song>>. The project is to run search of individual words in a string, in this case, song lyrics. I have three tests to determine the course of the map insertions, and my algorithm goes:
test if word has more than one character and is not a common word
if map already contains the word as a key, test if set already contains the song
if true, increment insertion counter
if map doesn't contain word as key
make new node, add song to set
increment counter
I declare the counter as private double insertions; as a class variable.
It is initialized in the constructor:
public SearchByLyricsWords(SongCollection sc) {
this.songs= sc.getAllSongs();
buildSongMap();
insertions=0;
totalReferences=0;
averageReferences=0;
}
The buildMap method:
for (String word:currentLyrics) {
if (word.length()>1 && !commonWords.contains(word)) {
if (lyricWords.containsKey(word)) {
if (!lyricWords.get(word).contains(song))
insertions++; //this is a non-duplicate song in the set
lyricWords.get(word).add(song);
} else {
TreeSet<Song> songSet= new TreeSet<Song>();
songSet.add(song);
lyricWords.put(word, songSet);
keyWords.add(word);
insertions++;
}
//System.out.println(word+" added");
}
} //end loop through string
Why is a class variable that is modified in a method, not then giving the correct value in another method?
Try
public SearchByLyricsWords(SongCollection sc) {
this.songs= sc.getAllSongs();
insertions=0;
totalReferences=0;
averageReferences=0;
buildSongMap();
}
It looks like you are setting the variable to zero right after calling the buildsongmap function.
As has already been mentioned, it's a matter of initialization in the constructor. One other thing: in your buildSongMap method, you are adding the song to the map regardless of whether or not it already contains it. Although you're using a Set, which will prevent duplicates, I think it's more readable to only perform the add in the case where it already does not exist.
if (!lyricWords.get(word).contains(song)) {
insertions++;
lyricWords.get(word).add(song);
}

Categories

Resources