Searching through an Array of Objects - java

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);

Related

Parametrisation of recursive method without global variable

As an example we're combing through the permutations of the integer 123456789. Inspired by Heap's algorithm, we have the following
public static ArrayList<String> comb(char[] seq, int n, ArrayList<String> box){
if(n == 1){
if (isSquare(Integer.valueOf(String.valueOf(seq)))) {
box.add(String.valueOf(seq));
}
} else {
for(int i=0; i<n; i++){
comb(seq,n-1, box);
int j;
if ((n%2)==0) {
j = i;
} else {
j = 0;
}
char temp = seq[n-1];
seq[n-1] = seq[j];
seq[j] = temp;
}
}
return box;
}
In the present case we're interested whether a particular permutation is a square of an integer. Realised by
public static boolean isSquare(int n) {
if ((n%10)==2 || (n%10) ==3 || (n%10)==7 || (n%10) == 8) {
return false;
} else if ( (Math.sqrt(n)) % 1 ==0) {
return true;
} else {
return false;
}
}
However, to be able to use comb I must initialise an empty array outside of the method. What should I do to avoid inducing the need for global variable? I would still like to obtain a box with all solutions. I realise my error is in the parametrisation of comb .
Create a function that "wraps" the original recursive function, provides it with every parameter it needs and creates copies of objects if necessary:
Let's say you renamed your comb(...) function to combRecursive(...) for the sake of convenient naming.
public static ArrayList<String> comb(char[] seq, int n){
char[] seqCopy = Arrays.copyOf(seq, seq.length);
return combRecursive(seqCopy, n, new ArrayList());
}

Need the Index No of an Array List, by giving the certain text of the element String

I want to get the particular index of the array list, by using only contained text. Say suppose,
I have arraylist as
Test = {"LabTechnician","SeniorLabTechnician_4","Pathologist","SeniorLabTechnician_6"}
If want the index nos of both the SeniorLabTechnician, i have to use the exact string in the indexOf and lastindexOf method. Like Test.indexOf("SeniorLabTechnician_4") and Test.lastindexOf("SeniorLabTechnician_6")
this is will get me the exact answer.. But instead of that,by using only prefix say like senior or some thing like, i want the exact same answer before..
Like
Test.indexOf("Senior") and Test.lastindexOf("Senior")...
Please suggest
Loop over the list and compare the elements with contains:
int indexOfContains(List<String> lst, String what) {
for(int i=0;i<lst.size();i++){
//this will make the check case insensitive, see JAVY's comment below:
//if(lst[i].toLowerCase().contains(what.toLowerCase())) {
if(lst[i].contains(what)){
return i;
}
}
return -1;
}
If you want something like lastIndexOf then just reverse the order in which the list is iterated.
As I understand, you want to modify default behaviour of indexOf and lastIndexOf methods of ArrayList.
My solution is create a new class CustomArrayList extends ArrayList.
Override indexOf method
Override lastIndexOf method
public class CustomArrayList extends ArrayList {
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size(); i++)
if (get(i) == null)
return i;
} else {
for (int i = 0; i < size(); i++)
if(o instanceof String) {
if(get(i).toString().startsWith(o.toString())) {
return i;
}
} else {
if (o.equals(get(i)))
return i;
}
}
return -1;
}
public static void main(String[] args) {
List list = new CustomArrayList();
list.add("LabTechnician");
list.add("SeniorLabTechnician_4");
list.add("Pathologist");
list.add("SeniorLabTechnician_6");
System.out.println(list.indexOf("Senior"));
}
}
I left overriding of lastindexof method for you.
private int getsearchPos(String searchvalue) {
for(String hj : Test)
{
if(hj.toLowerCase().startsWith(searchvalue.toLowerCase()))
return Test.indexOf(hj);
}
return -1;
}
this should help.

Java Arrays[] - Assigning Specific Elements in a For Loop to Certain Values

I was attempting to write some code for a program in BlueJ (Java) that lists bags and adds and removes items from those bags, that sort of thing. Then I got stuck in the first class; I couldn't get to add an item to the bag properly as you can notice below in the addItem() method; it keeps adding String s to every null element in the array rather the first encountered. Any help would be tremendously appreciated.
Best wishes & many thanks,
Xenos
public class Bag1 {
private String[] store; // This is an array holding mutlitple strings.
public Bag1(int storageCapacity) {
store = new String[storageCapacity];
} // That was the primitive array constructor.
public boolean isFull() {
boolean full = true;
for(int i = 0; i < store.length; i++) {
if(store[i] == null) {
full = false;
}
}
return full;
} // The method above checks if the bag is full or not, and returns a boolean value on that basis.
public void add(String s) {
for(int i = store.length; i >= 0; i--) {
if(store[i] == null) {
store[i] = s;
}
}
}
}
You should exit the loop after finding the first empty spot :
public void add(String s)
{
for(int i=store.length-1; i>=0; i--) { // note the change in the starting index
if(store[i]==null) {
store[i] = s;
break;
}
}
}

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;
}
}

NullPointerException in add() Method

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);
}

Categories