Java HashMaps with bukkit - java

And how to add 2 enchantments at once in bukkit with
myItem.addEnchantments( Enchantment.KNOCKBACK, 1 /* TODO Here goes 2nd enchantment */ );
'addEnchantments' accepts 'addEnchantments(Map < Enchantment, int >)'

You rather use addEnchantment twice (or more):
myItem.addEnchantment(Enchantment.KNOCKBACK, 1);
myItem.addEnchantment(Enchantment.THRONS, 2);
If you insist on using addEnchantments you'll need to create a map, populate it and pass it:
Map<Enhancement, Integer> map = new HashMap<Enhancement, Integer>();
map.put(Enchantment.KNOCKBACK, 1);
map.put(Enchantment.THRONS, 2);
myItem.addEnchantments(map);
In your case, I would go with option 1

#John Smith's second question: (How to convert string to hashmap)
You can convert hashmap to string but java (as I know) doesn't have string to hashmap. You can make a function that does this (might be impossible) or make a couple functions that convert hashmap to string and string to hashmap. In this case you want a hashmap with Enchantment and an Integer, so you would simply do something like this:
public /*static*/ String hashMapToString(HashMap<Enchantment, Integer> hashMap) {
StringBuilder serializedString = new StringBuilder();
for (Enchantment enchant : hashMap.keySet()) {
serializedString.append(enchant.getName() + "<>" + hashMap.get(enchant) + ";");
}
return serializedString.toString();
}
then you would create a function to convert that back to a hashmap:
public /*static*/ HashMap<Enchantment, Integer> stringToHashMap(String hashMapString) {
HashMap<Enchantment, Integer> hashMap = new HashMap<>();
for (String split : hashMapString.split(";")) {
String[] splited = split.split("<>");
hashMap.put(Enchantment.getByName(splited[0]), Integer.valueOf(splited[1]))
}
return hashMap;
}
You can even make them static (remove the comment marks and if you don't want it at all just remove what is inside the comment marks with the comment marks)

Related

assign mapped value to input string

I am not able to get the value of the string i have entered according to my mapped values??
I want the value which i want to get as 8118198920
import java.util.*;
class maptable1 {
public static void main(String args[]) {
HashMap<String, Integer> hm =
new HashMap<String, Integer>();
hm.put("A", Integer.valueOf(1));
hm.put("B", Integer.valueOf(2));
hm.put("C", Integer.valueOf(3));
hm.put("D", Integer.valueOf(4));
hm.put("E", Integer.valueOf(5));
hm.put("F", Integer.valueOf(6));
hm.put("G", Integer.valueOf(7));
hm.put("H", Integer.valueOf(8));
hm.put("I", Integer.valueOf(9));
hm.put("J", Integer.valueOf(10));
hm.put("K", Integer.valueOf(11));
hm.put("L", Integer.valueOf(12));
hm.put("M", Integer.valueOf(13));
hm.put("N", Integer.valueOf(14));
hm.put("O", Integer.valueOf(15));
hm.put("P", Integer.valueOf(16));
hm.put("Q", Integer.valueOf(17));
hm.put("R", Integer.valueOf(18));
hm.put("S", Integer.valueOf(19));
hm.put("T", Integer.valueOf(20));
hm.put("U", Integer.valueOf(21));
hm.put("V", Integer.valueOf(22));
hm.put("W", Integer.valueOf(23));
hm.put("X", Integer.valueOf(24));
hm.put("Y", Integer.valueOf(25));
hm.put("Z", Integer.valueOf(26));
System.out.println("The Value is: " + hm.get("HARSHIT"));
}
}
Hash maps don't work like that.
To produce what you want, you need to call hm.get() with each character in the string, convert the integer you get to a string, and join all of these strings together.
One way to implement this is to use streams:
// "s" is a string variable containing "HARSHIT"
String result = s.chars().mapToObj(x -> Character.toString((char)x))
.map(x -> Integer.toString(hm.get(x)))
.collect(Collectors.joining());
Also note that you don't need Integer.valueOf. You can just use the integer itself.

Calculate value of text from a dictionary of words in Java 8

I'm having trouble transforming my algo in a Java 8 view.
I have an arrayList composed of Articles
ArrayList<Article> listArticles = new ArrayList<>();
With an Article composed like this
public class Article {
private String titleArticle;
private String abstractArticle;
private String textArticle;
private Long value;
}
and on the other side I have map of words with each one a value associated
HashMap<String, Long> dictionary = new HashMap<>();
I want to get the value of an article. The value of an article is calculated based on the words in the title, abstract and text (all added up together)
In Java 7 I would do something like this (I hope I didn't make any mistake here)
for(Article article : dataArticles){
double valueArticle = 0;
for(Map.Entry<String, Long> word : dataDictionary.entrySet()){
//looping through the words in the title
for(String text : article.getTitle().split(" ")){
if(text.equalsIgnoreCase(word.getKey())){
valueArticle += word.getValue();
}
}
//looping through the words in the abstract
for(String text : article.getAbstractText().split(" ")){
if(text.equalsIgnoreCase(word.getKey())){
valueArticle += word.getValue();
}
}
//looping through the words in the abstract
for(String text : article.getText().split(" ")){
if(text.equalsIgnoreCase(word.getKey())){
valueArticle += word.getValue();
}
}
}
article.setValue(valueArticle);
}
How can I calculate the value of each article inside the Array by reducing the time process?
I was thinking of using lambdas but maybe it's a bad approach.
I'm new to Java 8 and trying to learn it.
After some developing
Still looking around how to make my ArrayList using streams. In the meantime I wanted, as well, to sort out the list from greatest article value to lowest article value.
I imagined that it would be something like this
Comparator<Article> byArticleValue = (a1, a2) ->
Integer.compare(a1.getValue(), a2.getValue());
dataArticles.stream()
.sorted(byArticleValue);
But my list comes out unsorted. What am I doing wrong in this case ?
The hash map can do very fast lookups. If you reorganize your code a bit, you can get huge runtime savings.
long getValueOfText(String text) {
long value = 0;
for(String word : text.split(" ")) {
Long v = dataDictionary.get(word);
if (v != null) {
value += v;
}
}
return value;
}
That call to get is almost free. No matter how many words you store in your map, it will take a constant time to look one up.
EDIT: it looks a bit nicer as a Java 8 stream
long getValueOfText(String text) {
return Arrays.stream(text.split(" "))
.map(word -> dataDictionary.get(word))
.filter(v -> v != null)
.reduce(Long::sum).get();
}
If your dictionary keys are not lower case, you should create a lower-cased version and re-use it:
/**
* Create a copy of the dictionary with all keys in lower case.
* #param lc a dictionary of lowercase words to their value
* #param article the article to be evaluated
*/
static Map<String, Double> convert(Map<String, Double> dictionary)
{
return
dictionary.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().toLowerCase(),
Map.Entry::getValue,
(p, q) -> p + q));
}
Then, for each article, you can quickly compute a value using a stream pipeline:
/**
* Compute the value of an article.
* #param lc a dictionary of lowercase words to their value
* #param article the article to be evaluated
*/
static double evaluate(Map<String, Double> lc, Article article)
{
return
Stream.of(article.getTitle(), article.getAbstractText(), article.getText())
.flatMap(s -> Arrays.stream(s.toLowerCase().split(" ")))
.mapToDouble(k -> lc.getOrDefault(k, 0D))
.sum();
}
For more flexibility in folding words together, you could use a Collator to index with a CollationKey rather than lowercase words. A similar enhancement could be made for tokenizing the text, rather than simply splitting on spaces.
The Java 8 way of doing this is by utilizing Streams.
You can read about them here: http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html & Part 2: http://www.oracle.com/technetwork/articles/java/architect-streams-pt2-2227132.html
Here is some sample code:
public static Map<string, integer=""> wordCount(Stream<String> stream) {
return stream
.flatMap(s -> Stream.of(s.split("\\s+")))
.collect(Collectors
.toMap(s -> s, s -> 1, Integer::sum));
}
Instead of looping through elements, you can process the data with a stream and use its methods to sort and organize through it. In the sample code above, the flatmap method separates lines of text into words and the collect method gathers them into a Map<String, Integer>, with the key being the word and the value being its count.
Java8 Streaming API is the way to go. It will make your code much faster and allows optional multi-threading.
I rewrote your code into this compilable example:
public class Snippet {
static ArrayList<Article> listArticles = new ArrayList<>();
static HashMap<String, Long> dictionary = new HashMap<>();
private static void calculateWordValueSums(ArrayList<Article> listArticles) {
// turn your list of articles into a stream
listArticles.stream()
// allow multi-threading (remove this line if you expect to have few articles)
.parallel()
// make calculation per article
.forEach(article -> {
// set the "value" field in the article as the result
article.value =
// combine title, abstract and text, since they are counting all together
Stream.of(article.titleArticle, article.abstractArticle, article.textArticle)
// split every text into words (consider "\s" for to allow tabs as separators)
.flatMap(text -> Arrays.stream(text.split(" ")))
// allow multi-threading (remove this line if you expect to have few words per article)
.parallel()
// convert words into their corresponding integer value
.mapToLong(dictionary::get)
// sum all Longs
.sum();
System.out.println(article.value);
});
}
public static void main(String[] args) {
Article a = new Article();
a.titleArticle = "a b c";
a.abstractArticle = "d e";
a.textArticle = "f g h";
listArticles.add(a);
dictionary.put("a", 1l);
dictionary.put("b", 1l);
dictionary.put("c", 1l);
dictionary.put("d", 1l);
dictionary.put("e", 1l);
dictionary.put("f", 1l);
dictionary.put("g", 1l);
dictionary.put("h", 1l);
calculateWordValueSums(listArticles);
}
}
class Article {
String titleArticle;
String abstractArticle;
String textArticle;
long value;
}
You should, however, rethink your Article class. The field value will be null, until the calculation is done. Consider having an Article class with just the inputs for the calculation and an ArticleWithResultValue class, which contains a reference to the article and the resulting value. This will give you compiler help, about whether or not the calculation is already done.

Elegant solution for string-counting?

The problem I have is an example of something I've seen often. I have a series of strings (one string per line, lets say) as input, and all I need to do is return how many times each string has appeared. What is the most elegant way to solve this, without using a trie or other string-specific structure? The solution I've used in the past has been to use a hashtable-esque collection of custom-made (String, integer) objects that implements Comparable to keep track of how many times each string has appeared, but this method seems clunky for several reasons:
1) This method requires the creation of a comparable function which is identical to the String's.compareTo().
2) The impression that I get is that I'm misusing TreeSet, which has been my collection of choice. Updating the counter for a given string requires checking to see if the object is in the set, removing the object, updating the object, and then reinserting it. This seems wrong.
Is there a more clever way to solve this problem? Perhaps there is a better Collections interface I could use to solve this problem?
Thanks.
One posibility can be:
public class Counter {
public int count = 1;
}
public void count(String[] values) {
Map<String, Counter> stringMap = new HashMap<String, Counter>();
for (String value : values) {
Counter count = stringMap.get(value);
if (count != null) {
count.count++;
} else {
stringMap.put(value, new Counter());
}
}
}
In this way you still need to keep a map but at least you don't need to regenerate the entry every time you match a new string, you can access the Counter class, which is a wrapper of integer and increase the value by one, optimizing the access to the array
TreeMap is much better for this problem, or better yet, Guava's Multiset.
To use a TreeMap, you'd use something like
Map<String, Integer> map = new TreeMap<>();
for (String word : words) {
Integer count = map.get(word);
if (count == null) {
map.put(word, 1);
} else {
map.put(word, count + 1);
}
}
// print out each word and each count:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.printf("Word: %s Count: %d%n", entry.getKey(), entry.getValue());
}
Integer theCount = map.get("the");
if (theCount == null) {
theCount = 0;
}
System.out.println(theCount); // number of times "the" appeared, or null
Multiset would be much simpler than that; you'd just write
Multiset<String> multiset = TreeMultiset.create();
for (String word : words) {
multiset.add(word);
}
for (Multiset.Entry<String> entry : multiset.entrySet()) {
System.out.printf("Word: %s Count: %d%n", entry.getElement(), entry.getCount());
}
System.out.println(multiset.count("the")); // number of times "the" appeared
You can use a hash-map (no need to "create a comparable function"):
Map<String,Integer> count(String[] strings)
{
Map<String,Integer> map = new HashMap<String,Integer>();
for (String key : strings)
{
Integer value = map.get(key);
if (value == null)
map.put(key,1);
else
map.put(key,value+1);
}
return map;
}
Here is how you can use this method in order to print (for example) the string-count of your input:
Map<String,Integer> map = count(input);
for (String key : map.keySet())
System.out.println(key+" "+map.get(key));
You can use a Bag data structure from the Apache Commons Collection, like the HashBag.
A Bag does exactly what you need: It keeps track of how often an element got added to the collections.
HashBag<String> bag = new HashBag<>();
bag.add("foo");
bag.add("foo");
bag.getCount("foo"); // 2

Treemap with <Integer, List>

I'm going count the most used words in a text and I want to make it this way just need little help how i'm gonna fix the Treemap..
this is how its look like now ...
TreeMap<Integer, List<String>> Word = new TreeMap<Integer, List<String>>();
List<String> TheList = new ArrayList<String>();
//While there is still something to read..
while (scanner.hasNext()) {
String NewWord = scanner.next().toLowerCase();
if (Word.containsKey(NewWord)) {
Word.put(HERE I NEED HELP);
} else {
Word.put(HERE I NEED HELP);
}
}
So what i wanna do is if the NewWord is in the list then add one on Integer(key) and if not Add the word to the next list.
Your type appears to be completely incorrect
... if you want a frequency count
You want to have your word as the key and the count as the value. There is little value in using a sorted collection, but it is many time slower so I would use a HashMap.
Map<String, Integer> frequencyCount = new HashMap<>();
while (scanner.hasNext()) {
String word = scanner.next().toLowerCase();
Integer count = frequencyCount.get(word);
if (count == null)
frequencyCount.put(word, 1);
else
frequencyCount.put(word, 1 + count);
}
... if you want to key by length. I would use a List<Set<String>> This is because your word length is positive and bounded, and you want to ignore duplicate words which is something a Set is designed to do.
List<Set<String>> wordsByLength = new ArrayList<Set<String>>();
while (scanner.hasNext()) {
String word = scanner.next().toLowerCase();
// grow the array list as required.
while(wordsByteLength.size() <= word.length())
wordsByLength.add(new HashSet<String>());
// add the word ignoring duplicates.
wordsByLength.get(words.length()).add(word);
}
All the examples above are correctly storing the count into a map, unfortunately they are not sorting by count which is a requirement you also have.
Do not use a TreeMap, instead use a HashMap to build up the values.
Once you have the complete list of values built you can then drop the entrySet from the HashMap into a new ArrayList and sort that array list by Entry<String,Integer>.getValue().
Or to be neater create a new "Count" object which has both the word and the count in and use that.
Dont do..
TreeMap<Integer, List<String>>
instead do,
TreeMap<String, Integer> // String represents the word... Integer represents the count
because your key (count) can be same sometimes where as the words will be unique...
Do it the other way around... keep reading the words and check if your map contains that word... If yes, increment the count, else add the word with count = 1.
Try this one
TreeMap<String, Integer> Word = new TreeMap<String,Integer>();
while (scanner.hasNext()) {
String NewWord = scanner.next().toLowerCase();
if (Word.containsKey(NewWord)) {
Word.put(NewWord,Word.get(NewWord)+1);
} else {
Word.put(NewWord,1);
}
}
The way to solve this in a time-efficient manner is to have two maps. One map should be from keys to counts, and the other from counts to keys. You can assemble these in different passes. The first should assemble the map from keys to counts:
Map<String, Integer> wordCount = new HashMap<String,Integer>();
while (scanner.hasNext()) {
String word = scanner.next().toLowerCase();
wordCount.put(word, wordCount.containsKey(word) ? wordCount.get(word) + 1 : 1);
}
The second phase inverts the map so that you can read off the top-most keys:
// Biggest values first!
Map<Integer,List<String>> wordsByFreq = new TreeMap<Integer,List<String>>(new Comparator<Integer>(){
public int compare(Integer a, Integer b) {
return a - b;
}
});
for (Map.Entry<String,Integer> e : wordCount) {
List<String> current = wordsByFreq.get(e.getValue());
if (current == null)
wordsByFreq.put(e.getValue(), current = new ArrayList<String>());
current.add(e.getKey());
}
Note that the first stage uses a HashMap because we don't need the order at all; just speedy access. The second stage needs a TreeMap and it needs a non-standard comparator so that the first value read out will be the list of most-frequent words (allowing for two or more words to be most-frequent).
Try this out:
TreeMap<String, Integer> map = new TreeMap<String, Integer>();
Scanner scanner = null;
while (scanner.hasNext()) {
String NewWord = scanner.next().toLowerCase();
if (map.containsKey(NewWord)) {
Integer count = map.get(NewWord);
// Add the element back along with incremented count
map.put(NewWord, count++);
} else {
map.put(NewWord,1); // Add a new entry
}
}

Java Parsing Using Hmap

I am new to Java. I want to Parse the data which is in this Format
Apple;Mango;Orange:1234;Orange:1244;...;
There could be more than one "Orange" at any point of time. Numbers (1,2...) increase and accordingly as the "Orange".
Okay. After splitting it, Lets assume I have stored the first two data(Apple, Orange) in a variable(in setter) to return the same in the getter function. And now I want to add the value(1234,1244....etc) in the 'orange' thing into a variable to return it later. Before that i have to check how many oranges have come. For that, i know i have to use for loop. But don't know how to store the "Value" into a variable.
Please Help me guys.
String input = "Apple;Mango;Orange:1234;Orange:1244;...;"
String values[] = input.split(";");
String value1 = values[0];
String value2 = values[1];
Hashmap< String, ArrayList<String> > map = new HashMap<String, ArrayList<String>>();
for(int i = 2; i < values.length; i = i + 2){
String key = values[i];
String id = values[i+1];
if (map.get(key) == null){
map.put(key, new ArrayList<String>());
}
map.get(key).add(id);
}
//for any key s:
// get the values of s
map.get(s); // returns a list of all values added
// get the count of s
map.get(s).size(); // return the total number of values.
Let me try to rephrase the question by how I interpreted it and -- more importantly -- how it focuses on the input and output (expectations), not the actual implementation:
I need to parse the string
"Apple;Mango;Orange:1234;Orange:1244;...;"
in a way so I can retrieve the values associated (numbers after ':') with the fruits:
I should receive an empty list for both the Apple and Mango in the example, because they have no value;
I should receive a list of 1234, 1244 for Orange.
Of course your intuition of HashMap is right on the spot, but someone may always present a better solution if you don't get too involved with the specifics.
There are a few white spots left:
Should the fruits without values have a default value given?
Should the fruits without values be in the map at all?
How input errors should be handled?
How duplicate values should be handled?
Given this context, we can start writing code:
import java.util.*;
public class FruitMarker {
public static void main(String[] args) {
String input = "Apple;Mango;Orange:1234;Orange:1244";
// replace with parameter processing from 'args'
// avoid direct implementations in variable definitions
// also observe the naming referring to the function of the variable
Map<String, Collection<Integer>> fruitIds = new HashMap<String, Collection<Integer>>();
// iterate through items by splitting
for (String item : input.split(";")) {
String[] fruitAndId = item.split(":"); // this will return the same item in an array, if separator is not found
String fruitName = fruitAndId[0];
boolean hasValue = fruitAndId.length > 1;
Collection<Integer> values = fruitIds.get(fruitName);
// if we are accessing the key for the first time, we have to set its value
if (values == null) {
values = new ArrayList<Integer>(); // here I can use concrete implementation
fruitIds.put(fruitName, values); // be sure to put it back in the map
}
if (hasValue) {
int fruitValue = Integer.parseInt(fruitAndId[1]);
values.add(fruitValue);
}
}
// display the entries in table iteratively
for (Map.Entry<String, Collection<Integer>> entry : fruitIds.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
}
}
If you execute this code, you will get the following output:
Mango => []
Apple => []
Orange => [1234, 1244]

Categories

Resources