NullPointerException in add() Method - java

My problem is I created an add() method for my ArrayList.
I get an NullPointerException. How can I implement an add() method in my class as the following code suggests?
here is the code:
public class XY{
private List<DictEntry> dict = new ArrayList<DictEntry>();
public void add(String word, int frequency) {
DictEntry neu = new DictEntry(word, frequency);
if (word == null || frequency == 0) {
return;
}
if (!dict.isEmpty()) {
for (int i = 0; i < dict.size(); i++) {
if (dict.get(i).getWord() == word) {
return;
}
}
}
dict.add(neu);
}
}

You have a null element in your array. dict.get(i).getWord() is like null.getWord()

Without the line number it's thrown on, it's harder to say. But I'd suggest not taking the approach you are, anyhow.
First off: don't reimplement functionality that exists:
public class XY{
private List<DictEntry> dict = new ArrayList<DictEntry>();
public void add(String word, int frequency) {
if (word == null || frequency == 0) {
return;
}
DictEntry neu = new DictEntry(word, frequency);
if (!dict.contains(word)) {
dict.add(word);
}
}
}
Even better, use a structure more appropriate to the problem. You're mapping a word to a count - that's all that you appear to be doing with the DictEntry, here. So why not:
public class XY{
private Map<String, Integer> dict = new HashMap<String, Integer>();
public void add(String word, int frequency) {
dict.put(word, frequency);
}

Related

Performance issue due to recursivity usage

I have a performance issue when I execute my code below. It is using recursive function. For now, it takes me 10670 ms to run it. Can someone help me to improve it? I am using java 8 but as I am not familiar yet with it, I did not implement it with java 8. I red online, it says that java 8 can improve performance but can make performance as well depending of the amount of data you manipulate. Thanks all
public static void RemoveDuplicateData(List<VariableDataGroup> variableDataGroups) {
if (variableDataGroups == null) {
return;
}
for (VariableDataGroup varDataGroup : variableDataGroups) {
RemoveDuplicateData(varDataGroup.getOrDataList());
if (varDataGroup.getAndDataList() != null) {
removeAnyDuplicateAndBlankCodesFromAndDataList(varDataGroup);
}
if (varDataGroup.getNotDataList() != null) {
removeAnyDuplicateAndBlankCodesFromNotDataList(varDataGroup);
}
}
}
private static void removeAnyDuplicateAndBlankCodesFromAndDataList(VariableDataGroup varDataGroup) {
for (int x = (varDataGroup.getAndDataList().size()-1) ; x >= 0; x--) {
if (varDataGroup.getAndDataList().get(x) == null || varDataGroup.getAndDataList().get(x).isEmpty())
{
varDataGroup.getAndDataList().remove(x);
} else {
for (int y = 0; y < x; y++) {
if (varDataGroup.getAndDataList().get(x).equals(varDataGroup.getAndDataList().get(y))) {
varDataGroup.getAndDataList().remove(x);
break;
}
}
}
}
}
private static void removeAnyDuplicateAndBlankCodesFromNotDataList(VariableDataGroup varDataGroup) {
for (int x = (varDataGroup.getNotDataList().size()-1) ; x >= 0; x--) {
if (varDataGroup.getNotDataList().get(x) == null || varDataGroup.getNotDataList().get(x).isEmpty())
{
varDataGroup.getNotDataList().remove(x);
} else {
for (int y = 0; y < x; y++) {
if (varDataGroup.getNotDataList().get(x).equals(varDataGroup.getNotDataList().get(y))) {
varDataGroup.getNotDataList().remove(x);
break;
}
}
}
}
}
public class VariableDataGroup {
private String appearingData = "";
private boolean dataFound ;
private List<String> notDataList = new ArrayList();
private List<String> andDataList = new ArrayList();
private List<VariableGroup> orDataList = new ArrayList();
...
}
Thanks Andy Turner and everyone for your help and advice. Here is what I do then.
private static void removeDuplicateAndEmptyData(VariableDataGroup varDataGroup) {
Set<String> dedupedAndDataSet = new LinkedHashSet<>();
List<String> andDataList = varDataGroup.getAndDataList();
Set<String> dedupedNotDataSet = new LinkedHashSet<>();
List<String> notDataList = varDataGroup.getNotDataList();
for (String s : andDataList) {
if (s != null && !s.isEmpty()) {
dedupedAndDataSet.add(s);
}
}
andDataList.clear();
andDataList.addAll(dedupedAndDataSet);
for (String s : notDataList) {
if (s != null && !s.isEmpty()) {
dedupedNotDataSet.add(s);
}
}
notDataList.clear();
notDataList.addAll(dedupedNotDataSet);
}
public static void RemoveDuplicateData(List<VariableDataGroup> variableDataGroups) {
if (variableDataGroups == null) {
return;
}
for (VariableDataGroup varDataGroup : variableDataGroups) {
RemoveDuplicateData(varDataGroup.getOrDataList());
if (varDataGroup.getAndDataList() != null) {
removeDuplicateAndEmptyData(varDataGroup);
}
if (varDataGroup.getNotDataList() != null) {
removeDuplicateAndEmptyData(varDataGroup);
}
}
}
As I commented above, it is hard to offer much help, as we don't know anything about the amount of data you are processing.
However, you would be well served to use Sets instead of Lists to do your deduplication.
For example, your removeAnyDuplicateAndBlankCodesFromAndDataList could be written like this:
private static void removeAnyDuplicateAndBlankCodesFromAndDataList(VariableDataGroup varDataGroup) {
List<String> list = varDataGroup.getAndDataList();
// Copy the list into the set - this removes duplicates.
Set<String> deduped = new LinkedHashSet<>(list);
// Remove the null and empty string, if they are present.
deduped.remove("");
deduped.remove(null);
// Replace the list contents with those of deduped.
list.clear();
list.addAll(deduped);
}
This simply does a lot less work than with the List: Sets automatically contain no duplicates, and repeatedly removing single elements from an ArrayList is quite inefficient (unless it is at the end).
Note that everything from the // Copy the list into the set comment downwards works on "some list" - so you don't need to duplicate this method for the not list, you can simply change the method to accept the list as the parameter:
private static void removeDuplicates(List<String> list) {
// ...
}
Then invoke like this:
if (varDataGroup.getAndDataList() != null) {
removeDuplicates(varDataGroup.getAndDataList());
}
if (varDataGroup.getNotDataList() != null) {
removeDuplicates(varDataGroup.getNotDataList());
}
(and you could even move the null check into the method, to avoid duplicating that).
Of course, you could also just declare the andDataList as a Set in the first place, then you'd not have to worry about the duplicates (although you would have to somehow filter the null and empty strings).
private Set<String> andDataList = new LinkedHashSet<>();

Java - return the key with the longest ArrayList in Hashmap<Class,ArrayList<Class>>

I've been trying to modify the code from top answers from a similar question here, but I can't get it to work for arraylist lengths
Get the keys with the biggest values from a hashmap?
Lets say I have
HashMap<Customer,ArrayList<Call>> outgoingCalls = new HashMap<Customer,ArrayList<Call>>();
When the program runs, it stores every call made in the hashmap. I want to run through this hashmap and return the Customer who has made the most calls. I've been trying to modify this code from the link above but I'm completely lost
Entry<Customer,ArrayList<Call> mostCalls = null;
for(Entry<String,ArrayList<Call> e : outgoingCalls.entrySet()) {
if (mostCalls == null || e.getValue() > mostCalls.getValue()) {
mostCalls = e;
Close, but not quite.
Entry<Customer,ArrayList<Call>> mostCalls = null;
for(Entry<String,ArrayList<Call>> e : outgoingCalls.entrySet()) {
if (mostCalls == null || e.getValue().size() > mostCalls.getValue().size()) {
mostCalls = e;
}
}
You can try this out. You will not need any extra imports.
int maxSize = Integer.MIN_VALUE;
for(Customer e: outgoingCalls.keySet()) {
if (maxSize < outgoingCalls.get(e).size()) {
maxSize = outgoingCalls.get(e).size();
mostCalls = e;
}
}
public class T {
public static void main(String[] args) {
List<Customer> customerList = new ArrayList<Customer>();
customerList.add(new Customer());
Collections.sort(customerList, new Comparator<Customer>() {
#Override
public int compare(Customer c1, Customer c2) {
return c1.callsMadeByCustomer.size() - c2.callsMadeByCustomer.size();
}
});
System.out.println("Most Calls: " + customerList.get(customerList.size() - 1));
}
}
class Customer {
ArrayList<Call> callsMadeByCustomer;
public Customer() {
callsMadeByCustomer = new ArrayList<Call>();
}
}
You can even organise it like this. So now callsMadeByCustomer are inside the customer class.

Searching through an Array of Objects

I'm attempting to return the index of where an object appears in an array of objects.
public static int search(WordCount[] list,WordCount word, int n)
{
int result = -1;
int i=0;
while (result < 0 && i < n)
{
if (word.equals(list[i]))
{
result = i;
break;
}
i++;
}
return result;
}
WordCount[] is the array of objects.
word is an instance of WordCount.
n is the number of objects in WordCount[]
It runs, but isn't returning the index correctly. Any and all help is appreciated. Thanks for your time.
CLASS
class WordCount
{
String word;
int count;
static boolean compareByWord;
public WordCount(String aWord)
{
setWord(aWord);
count = 1;
}
private void setWord(String theWord)
{
word=theWord;
}
public void increment()
{
count=+1;
}
public static void sortByWord()
{
compareByWord = true;
}
public static void sortByCount()
{
compareByWord = false;
}
public String toString()
{
String result = String.format("%s (%d)",word, count);
return result;
}
}
How I'm calling it...
for (int i=0;i<tokens.length;i++)
{
if (tokens[i].length()>0)
{
WordCount word = new WordCount(tokens[i]);
int foundAt = search(wordList, word, n);
if (foundAt >= 0)
{
wordList[foundAt].increment();
}
else
{
wordList[n]=word;
n++;
}
}
}
}
By default, Object#equals just returns whether or not the two references refer to the same object (same as the == operator). Looking at what you are doing, what you need to do is create a method in your WordCount to return word, e.g.:
public String getWord() {
return word;
}
Then change your comparison in search from:
if (word.equals(list[i]))
to:
if (word.getWord().equals(list[i].getWord()))
Or change the signature of the method to accept a String so you don't create a new object if you don't have to.
I wouldn't recommend overriding equals in WordCount so that it uses only word to determine object equality because you have other fields. (For example, one would also expect that two counters were equal only if their counts were the same.)
The other way you can do this is to use a Map which is an associative container. An example is like this:
public static Map<String, WordCount> getCounts(String[] tokens) {
Map<String, WordCount> map = new TreeMap<String, WordCount>();
for(String t : tokens) {
WordCount count = map.get(t);
if(count == null) {
count = new WordCount(t);
map.put(t, count);
}
count.increment();
}
return map;
}
This method is probably not working because the implementation of .equals() you are using is not correctly checking if the two objects are equal.
You need to either override the equals() and hashCode() methods for your WordCount object, or have it return something you want to compare, i.e:word.getWord().equals(list[i].getWord())
It seems easier to use:
public static int search(WordCount[] list, WordCount word)
{
for(int i = 0; i < list.length; i++){
if(list[i] == word){
return i;
}
}
return -1;
}
This checks each value in the array and compares it against the word that you specified.
The odd thing in the current approach is that you have to create a new WordCount object in order to look for the count of a particular word. You could add a method like
public boolean hasEqualWord(WordCount other)
{
return word.equals(other.word);
}
in your WordCount class, and use it instead of the equals method:
....
while (result < 0 && i < n)
{
if (word.hasEqualWord(list[i])) // <--- Use it here!
{
....
}
}
But I'd recommend you to rethink what you are going to model there - and how. While it is not technically "wrong" to create a class that summarizes a word and its "count", there may be more elgant solutions. For example, when this is only about counting words, you could consider a map:
Map<String, Integer> counts = new LinkedHashMap<String, Integer>();
for (int i=0;i<tokens.length;i++)
{
if (tokens[i].length()>0)
{
Integer count = counts.get(tokens[i]);
if (count == null)
{
count = 0;
}
counts.put(tokens[i], count+1);
}
}
Afterwards, you can look up the number of occurrences of each word in this map:
String word = "SomeWord";
Integer count = counts.get(word);
System.out.println(word+" occurred "+count+" times);

How to get N most often words in given text, sorted from max to min?

I have been given a large text as input. I have made a HashMap that stores each different word as a key, and number of times that occurs as value (Integer).
Now I have to make a method called mostOften(int k):List that return a List that gives the first k-words that from max number of occurrence to min number of occurrence ( descending order ) using the HashMap that I have made before.
The problem is that whenever 2 words have the same number of occurrence, then they should be sorted alphabetically.
The first idea that was on my mind was to swap keys and values of the given HashMap, and put it into TreeMap and TreeMap will sort the words by the key(Integer - number of occurrence of the word ) and then just pop the last/first K-entries from the TreeMap.
But I will have collision for sure, when the number of 2 or 3 words are the same. I will compare the words alphabetically but what Integer should I put as a key of the second word comming.
Any ideas how to implement this, or other options ?
Hints:
Look at the javadocs for the Collections.sort methods ... both of them!
Look at the javadocs for Map.entries().
Think about how to implement a Comparator that compares instances of a class with two fields, using the 2nd as a "tie breaker" when the other compares as equal.
Here's the solution with I come up.
First you create a class MyWord that can store the String value of the word and the number of occurences it appears.
You implement the Comparable interface for this class to sort by occurences first and then alphabetically if the number of occurences is the same
Then for the most often method, you create a new List of MyWord from your original map. You add the entries of this to your List
You sort this list
You take the k-first items of this list using subList
You add those Strings to the List<String> and you return it
public class Test {
public static void main(String [] args){
Map<String, Integer> m = new HashMap<>();
m.put("hello",5);
m.put("halo",5);
m.put("this",2);
m.put("that",2);
m.put("good",1);
System.out.println(mostOften(m, 3));
}
public static List<String> mostOften(Map<String, Integer> m, int k){
List<MyWord> l = new ArrayList<>();
for(Map.Entry<String, Integer> entry : m.entrySet())
l.add(new MyWord(entry.getKey(), entry.getValue()));
Collections.sort(l);
List<String> list = new ArrayList<>();
for(MyWord w : l.subList(0, k))
list.add(w.word);
return list;
}
}
class MyWord implements Comparable<MyWord>{
public String word;
public int occurence;
public MyWord(String word, int occurence) {
super();
this.word = word;
this.occurence = occurence;
}
#Override
public int compareTo(MyWord arg0) {
int cmp = Integer.compare(arg0.occurence,this.occurence);
return cmp != 0 ? cmp : word.compareTo(arg0.word);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + occurence;
result = prime * result + ((word == null) ? 0 : word.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyWord other = (MyWord) obj;
if (occurence != other.occurence)
return false;
if (word == null) {
if (other.word != null)
return false;
} else if (!word.equals(other.word))
return false;
return true;
}
}
Output : [halo, hello, that]
In addition to your Map to store word counts I would use a PriorityQueue of fixed size K (with natural order). It will allow to reach O(N) complexity. Here is a code which use this approach:
In constructor we are reading input stream word by word filling the counters in the Map.
In the same time we are updating priority queue keeping it's max size = K (we need count top K words)
public class TopNWordsCounter
{
public static class WordCount
{
String word;
int count;
public WordCount(String word)
{
this.word = word;
this.count = 1;
}
}
private PriorityQueue<WordCount> pq;
private Map<String, WordCount> dict;
public TopNWordsCounter(Scanner scanner)
{
pq = new PriorityQueue<>(10, new Comparator<WordCount>()
{
#Override
public int compare(WordCount o1, WordCount o2)
{
return o2.count-o1.count;
}
});
dict = new HashMap<>();
while (scanner.hasNext())
{
String word = scanner.next();
WordCount wc = dict.get(word);
if (wc == null)
{
wc = new WordCount(word);
dict.put(word, wc);
}
if (pq.contains(wc))
{
pq.remove(wc);
wc.count++;
pq.add(wc);
}
else
{
wc.count++;
if (pq.size() < 10 || wc.count >= pq.peek().count)
{
pq.add(wc);
}
}
if (pq.size() > 10)
{
pq.poll();
}
}
}
public List<String> getTopTenWords()
{
Stack<String> topTen = new Stack<>();
while (!pq.isEmpty())
{
topTen.add(pq.poll().word);
}
return topTen;
}
}

Null ArrayList returned by TreeMap Java

I have to do a synonyms dictionary using a TreeMap. The TreeMap is of <Word, ArrayList<Word>> type. That means that for each key represented by a Word there will be a list of synonyms. When I want to list the contents of the dictionary, by using the method below, I discover that the ArrayList returned is null. What can I do? I tried tracing the code but I don't seem to find the error.
The method is :
public String listContent() {
Set set = wordList.keySet();
Iterator it = set.iterator();
String result = new String();
ArrayList<Word> words = new ArrayList<Word>();
while (it.hasNext()) {
Word temp = (Word) it.next();
words = wordList.get(temp);
if (words != null) {
Iterator it2 = words.iterator();
result += temp.getContent();
result += " - ";
int size = words.size();
while (it2.hasNext()) {
result += ((Word) it2.next()).getContent();
if (size != 1)
result += ", ";
size--;
}
result += "\n";
}
}
return result;
}
The ArrayList returned by wordList.get(temp) is null for some of the inserted elements. I checked the watches but there, they're not. What should I do ?
wordList is a TreeMap<Word, ArrayList<Word>>;
EDIT - the addWord method
public void addWord(String content1, String content2)
{
Word w1 = new Word(content1);
Word w2 = new Word(content2);
Set set = wordList.entrySet();
Iterator it = set.iterator();
boolean ok=false;
while(it.hasNext())
{
Map.Entry<Word,ArrayList<Word>> temp = (Map.Entry<Word,ArrayList<Word>>) it.next();
if(temp.getKey().getContent().matches(content1))
{
ArrayList<Word> words = temp.getValue();
Iterator it2 = words.iterator();
if(words.isEmpty()) words.add(w2);
else
{
boolean ok2=true;
while(it2.hasNext())
{
Word tempy = (Word) it2.next();
if(tempy.getContent().equals(content2))
{
ok2=false;
break;
}
}
if(ok2) words.add(w2);
}
ok=true;
}
}
if(!ok) {
ArrayList<Word> tempys = new ArrayList<Word>();
tempys.add(w2);
wordList.put(w1,tempys);
}
}
EDIT 2 - Word Class
public class Word implements Serializable,Comparable {
private String content;
public Word (String content)
{
this.content = content;
}
public void setContent(String content)
{
this.content=content;
}
public String getContent()
{
return content;
}
#Override
public int compareTo(Object o) {
if(((Word)o).getContent().equals(this.getContent())) return 0;
return 1;
}
}
Your compareTo method is wrong. The contract is that if A > B, then you must have B < A. Your implementation always returns 1 if the contents are not equal.
You should implement it like this:
#Override
public int compareTo(Word w) {
return this.content.compareTo(w.content);
}
(and the Word class should implement Comparable<Word>, not Comparable).
Since a TreeMap uses this method to tell if some word is bigger or smaller than another one, and since the method returns incoherent results, the Map also returns incoherent results.
Did you check that when you insert a synonym everything is ok?
BTW you should use StringBuilder for concatenating strings (better in perf) and you'd better use worklist.entrySet() for iterating on key and value at the same time, instead of several get and iterators.
The addWord method is a horrible mess and I'm getting a headache when I try to look at it, but my educated guess is that the system does not work because the Word class implements neither the equals method nor the hashCode method. Try adding these to it:
#Override
public int hashCode() {
return this.content.hashCode();
}
#Override
public boolean equals(Object o) {
return this.content.equals(o);
}
With those methods the TreeMap and the other structures are able to identify that two instances of Word classes that represent the same word are, indeed, equal.
I've cleaned up your existing code to use proper Java idioms, like for-each loop, StringBuilder instead of concatenating a String, avoid that size-- hack, stuff like that.
public String listContent() {
final StringBuilder result = new StringBuilder();
for (Map.Entry<Word, List<Word>> e : wordList.entrySet()) {
final List<Word> words = e.getValue();
if (words != null) {
result.append(e.getKey().getContent()).append(" - ");
final Iterator<Word> it = words.iterator();
result.append(it.next().getContent());
while(it.hasNext()) result.append(", ").append(it.next().getContent());
result.append("\n");
}
}
return result.toString();
}
Here's also a cleaned-up version of addWord, but still a heavy mess of program logic. If anyone has patience for this, I encourage him to steal and improve on this.
public void addWord(String content1, String content2) {
final Word w1 = new Word(content1), w2 = new Word(content2);
final Set<Map.Entry<Word, List<Word>>> set = wordList.entrySet();
for (Map.Entry<Word, List<Word>> temp : set) {
if (!temp.getKey().getContent().matches(content1)) {
final List<Word> newList = new ArrayList<Word>();
newList.add(w2);
wordList.put(w1,newList);
break;
}
final List<Word> words = temp.getValue();
if (words.isEmpty()) words.add(w2);
else {
for (Word w : words) {
if (w.getContent().equals(content2)) {
words.add(w2);
break;
}
}
}
}
}

Categories