Why is the key not being found in the hashmap? - java

I print out the key being searched for and the keys in the map and they are there but the assignment fails. I test by populating the map with one object and itterate through and print out the keys. The key I am referencing is there so I can't see how temp is null?
Birds temp = (Birds)hint.get(input.substring(0, input.length()-1).trim());//the last char is being dropped off on purpose
if(temp == null)
{
System.out.println("failed to map key");
Iterator entries = hint.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry thisEntry = (Map.Entry) entries.next();
System.out.println("Key1: "+
thisEntry.getKey()); //this an next line printout the same
System.out.println("key2: "+
input.substring(0, input.length()-1).trim());
}
}
I added the following lines to bird class but still the same problem
#Override public int hashCode()
{
return name.hashCode();
}
#Override
public boolean equals(Object obj) {
Bird b = (Bird)obj;
String str = b.name;
if(str.compareTo(this.name) == 0)
return true;
else
return false;
}
Turned out white space was screwing things up and I wasn't calling trim() often enough.

When you call substring, keep in mind that the ending index is not included in the substring.
The substring begins at the specified beginIndex and extends to the character at index endIndex - 1
In your call
input.substring(0, input.length()-1)
you are actually taking the last character off of whatever is currently in input. So, if you had a key "finch", you are inadvertently looking up the key "finc".
I don't see a reason for the substring call at all; remove it:
Birds temp = (Birds) hint.get(input.trim());
Additionally, the cast to Birds would be unnecessary if you supplied generic type parameters to your HashMap, something like this:
Map<String, Birds> hint = new HashMap<>();
Then, when calling get, you no longer need the cast:
Birds temp = hint.get(input.trim());

Related

Return a sorted List<Object> where first item value is always empty

Working with a list of Object where one of the item has an empty String. Trying to write method which would return a sorted list. By sorting means the first item value of the list should always be an empty String.
Since I don't want to manipulate the unsorted list, I am creating a new list to sort.
So far my code is:
private List<LoggerConfig> sort(List<LoggerConfig> unSortedList) {
List<LoggerConfig> sortedList = new ArrayList<LoggerConfig>(unSortedList);
//What to do here
return sortedList;
}
Looked at lot of SO posts but very confused.
You can trust the String.compareTo to match the order you seek. Here is a Comparator :
new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
return (o1.getName().compareTo(o2.getName()));
}
};
or directly implementing Comparable in the specific class (here Dummy)
class Dummy implements Comparable<Dummy>{
String name;
public int compareTo(Dummy o) {
return this.name.compareTo(o.name);
}
}
The why :
The String.compareTo check the first characters of both to find a difference (until the smallest length of both), if they match, the lengths are use to make the difference, the longest will be after the shortest (shortest.compareTo(longuest) will return an negative value (the length difference)).
In this case, "".compareTo("abc"), there is no character in the empty String, so the first check is skipped and the length is use to compare the Strings, so an empty String will always be seen as first compare to any "non-empty" String
An example with the previous Dummy class (just need to add the Constructor Dummy(String):
public class Main {
public static void main(String[] args) {
List<Dummy> dummies = new LinkedList<Dummy>();
dummies.add(new Dummy("abc.com.core"));
dummies.add(new Dummy(""));
dummies.add(new Dummy("abc.com.core.def"));
System.out.println("BEFORE : " + dummies);
Collections.sort(dummies);
System.out.println("AFTER : " + dummies);
}
}
Output :
BEFORE : [abc.com.core, , abc.com.core.def]
AFTER : [, abc.com.core, abc.com.core.def]
You can place this condition in your comparator so that elements with an empty value are considered "less" than other elements, so that it shows up at the beginning of the sorted list. Try something like this:
Collections.sort(sortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if(o1.getName().isEmpty(){
return -1;
}
if(o2.getName().isEmpty(){
return 1;
}
return (o1.getName().compareTo(o2.getName()));
}
});
I didn't test this, but this should make the idea clear. If the empty element shows up at the end of the list, swap the -1 and the 1.
If your List is huge and sorting takes a lot of time, it might be a better idea to remove the empty element before sorting, then sort, then place the element at the beginning.
The Comparator solution seems feasible to me; what you're missing is implementing the compare method so that it does what you want.
Collections.sort(sortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if(o1.getName().equals("")){
return -1;
} else if(o2.getName().equals("")) {
return 1;
} else {
return (o1.getName().compareTo(o2.getName()));
}
}
});
As per Java docs, the Comparator has a compare method that returns an int which is
less than 0 if the first argument is less than the second
0 if the arguments are equal
greater than 0 if the first argument is greater than the second
So the Comparator you need should return the comparison of the two strings if they're both different from "", and -1 (or 1) if the first (or second) String is empty.

Optimisation of searching HashMap with list of values

I have a map in which values have references to lists of objects.
//key1.getElements() - produces the following
[Element N330955311 ({}), Element N330955300 ({}), Element N3638066598 ({})]
I would like to search the list of every key and find the occurrence of a given element (>= 2).
Currently my approach to this is every slow, I have a lot of data and I know execution time is relative but it takes 40seconds~.
My approach..
public String occurance>=2 (String id)
//Search for id
//Outer loop through Map
//get first map value and return elements
//inner loop iterating through key.getElements()
//if match with id..then iterate count
//return Strings with count == 2 else return null
The reason why this is so slow is because I have a lot of ids which I'm searching for - 8000~ and I have 3000~ keys in my map. So its > 8000*3000*8000 (given that every id/element exists in the key/valueSet map at least once)
Please help me with a more efficient way to make this search. I'm not too deep into practicing Java, so perhaps there's something obvious I'm missing.
Edited in real code after request:
public void findAdjacents() {
for (int i = 0; i < nodeList.size(); i++) {
count = 0;
inter = null;
container = findIntersections(nodeList.get(i));
if (container != null) {
intersections.add(container);
}
}
}
public String findIntersections(String id) {
Set<Map.Entry<String, Element>> entrySet = wayList.entrySet();
for (Map.Entry entry : entrySet) {
w1 = (Way) wayList.get(entry.getKey());
for (Node n : w1.getNodes()) {
container2 = String.valueOf(n);
if (container2.contains(id)) {
count++;
}
if (count == 2) {
inter = id;
count = 0;
}
}
}
if (inter != (null))
return inter;
else
return null;
}
Based on the pseudocode provided by you, there is no need to iterate all the keys in the Map. You can directly do a get(id) on the map. If the Map has it, you will get the list of elements on which you can iterate and get the element if its count is > 2. If the id is not there then null will be returned. So in that case you can optimize your code a bit.
Thanks

How to remove minimum item from data array in Java?

I am working on a homework assignment in which I need to write a method that takes a data array and removes the minimum item from it. I am able to find the minimum item, but I am having trouble removing it. My code is below.
public Comparable removeMin() {
Iterator<T> it = iterator();
T min = it.next();
while (it.hasNext()) {
T next = it.next();
if (min.compareTo(next) > 0)
min = next;
it.remove();
}
System.out.println(min);
return min;
}
I have the print statement there just to verify that it is in fact getting the minimum item.
The code in main looks like this.
public static void main(String[] args) {
Bag<String> sbag = new Bag<String>();
sbag.add("Noriko");
sbag.add("Peter");
sbag.add("Buddy");
sbag.add("Mary");
sbag.removeMin();
}
When I run the sbag.removeMin(); command, the console prints "Buddy" which tells me that it is choosing "Buddy" as the min item. However, if I instead populate sbag with integers, it always prints the smallest integer, which indicates to me I have my code correct in that regard.
I have two questions.
1). When passing a list of strings such as above, how does Java determine which is smallest?
2). How can I fix my code so that it not only finds the minimum item, but also removes it?
First, it compares String based on the integral value of the characters in the String (e.g. ASCII) (but it does that because String implements Comparable<String>). I think you meant to return the generic type T, and you should check for an empty Collection. Finally, you need to iterate twice. Once to find the min the second to remove it.
public T removeMin() {
Iterator<T> it = iterator();
T min = (it.hasNext()) ? it.next() : null;
while (it.hasNext()) {
T next = it.next();
if (min.compareTo(next) > 0) {
min = next;
}
}
it = iterator(); // <-- start again
while (it.hasNext()) {
T next = it.next();
if (min.compareTo(next) == 0) {
it.remove();
break;
}
}
System.out.println(min);
return min;
}
It's using the ASCII code. In numeric byte values, B is lower in value than anything else you've got there.
Andto get rid of it, use array[n]="";

Most efficient way of finding common subexpressions in a list of strings in Java

I have a list of strings that represents package directories. I want to iterate the list, to find largest part of the strings where the packages are the same, then extract this substring, subtract that from the original list of strings to get specific packages so I create the appropriate directories.
I was thinking of creating the original list as a static hash set, then using the retainAll method, storing the result in a new String.
Would something like this be the most performant option, or is there a better way to do it?
Many thanks
This works for me, explanation in comments
// returns the length of the longest common prefix of all strings in the given array
public static int longestCommonPrefix(String[] strings) {
// Null or no contents, return 0
if (strings == null || strings.length == 0) {
return 0;
// only 1 element? return it's length
} else if (strings.length == 1 && strings[0] != null) {
return strings[0].length();
// more than 1
} else {
// copy the array and sort it on the lengths of the strings,
// shortest one first.
// this will raise a NullPointerException if an array element is null
String[] copy = Arrays.copyOf(strings, strings.length);
Arrays.sort(copy, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
int result = 0; // init result
// iterate through every letter of the shortest string
for (int i = 0; i < copy[0].length(); i++) {
// compare the corresponding char of all other strings
char currenChar = copy[0].charAt(i);
for (int j = 1; j < strings.length; j++) {
if (currenChar != copy[j].charAt(i)) { // mismatch
return result;
}
}
// all match
result++;
}
// done iterating through shortest string, all matched.
return result;
}
}
If changing the original array does not bother you, you can omit the line String[] copy = Arrays.copyOf(strings, strings.length); and just sort your strings array.
To retrieve the text, change the return type to String and return something like return copy[0].substring(0, result + 1); within the loop and return copy[0]; at the end of the method.
If you are just looking for the single most common package, I would do the following:
Grab the first element from the list (call it the reference package). Using this package name I would iterate through the list. For each remaining element in the list, see if the element contains the reference package. If so move to the next element. If not trim your reference package by one package (taking aa.bb.cc.serverside and converting to aa.bb.cc). Then see if the current element contains this new reference package. Repeat this until the reference package is empty or until the element matches. Then continue down the list of packages.
This will give you the largest most common package. Loop back through removing this from all elements in the list.
EDIT: Slight modification, better keep the . at the end of the package name to ensure complete package name.
Just sort them. The common prefixes will appear first.

Get values in TreeMap whose String keys start with a pattern

I have a Treemap with Strings as keys. I want to get all the values whose keys start with the String search.
I think what I need to do here is something like:
myTreeMap.subMap(search.concat(X1), true, search.concat(X2), true);
where X1 and X2 are the highest and lowest possible character.
Is there a better approach? If not, what are X1 and X2?
Thanks in advance.
basically you need lexicographically next prefix as the second boundary:
public <T> Map<String, T> subMapWithKeysThatAreSuffixes(String prefix, NavigableMap<String, T> map) {
if ("".equals(prefix)) return map;
String lastKey = createLexicographicallyNextStringOfTheSameLenght(prefix);
return map.subMap(prefix, true, lastKey, false);
}
String createLexicographicallyNextStringOfTheSameLenght(String input) {
final int lastCharPosition = input.length()-1;
String inputWithoutLastChar = input.substring(0, lastCharPosition);
char lastChar = input.charAt(lastCharPosition) ;
char incrementedLastChar = (char) (lastChar + 1);
return inputWithoutLastChar+incrementedLastChar;
}
Hmmmm. I would say you should do myTreeMap.subMap(search, true, search2, false) where search2 isn't concatenated, but is instead "incremented". After all, if X2 was just a character, then your implementation would miss search.concat(X2).concat(X2).
The problem is the partial key search your trying to do.
myTreeMap.subMap(search.concat(X1), true, search.concat(X2), true);
Let's assume you have some key/value pairs:
fooBar -> Some value
fooBage -> Some other value
barBear -> Running out of value ideas
barTender -> Another value
Now you want to find all "foo*", in this example fooBar and fooBage. The key is treated as a single token, that happens to be a string in this case. There is no way to treat the key as a partial key. Even saying you want "fooA" through "fooZ" won't get you fooBar, or fooBage.
If you make the key class (I'll call it FractionalKey), and override the equals method, then you can define equals as "some regex", or "either the entire thing, or just the first part" etc. the problem with this is that if equals returns true, then the hashcodes must also be equal, and this would break that rule I think.
I think this is your only option, other then searching the list of keys for the one you want.
Since my edit to the answer above was rejected for being too original, I'll post it here. This answer fixes typos and handles int overflow which the original did not.
public <T> Map<String, T> subMapWithKeysThatAreSuffixes(String prefix, NavigableMap<String, T> map) {
if ("".equals(prefix)) return map;
String lastKey = createLexicographicallyNextStringOfTheSameLength(prefix);
return map.subMap(prefix, true, lastKey, false);
}
String createLexicographicallyNextStringOfTheSameLength(String input) {
final int lastCharPosition = input.length()-1;
String inputWithoutLastChar = input.substring(0, lastCharPosition);
char lastChar = input.charAt(lastCharPosition);
char incrementedLastChar = (char) (lastChar + 1);
// Handle int/char overflow. This wasn't done above.
if (incrementedLastChar == ((char) 0)) return input+incrementedLastChar;
return inputWithoutLastChar+incrementedLastChar;
}

Categories