Contains.(cs) is case sensitive in android - java

I have a search method written onTextChanged. This will search an Arraylist of Hashmap. The problem here is that I get search results only for upper case or lower case.
How to solve this issue by making it not case sensitive.
Here is the code I have:
public void onTextChanged(CharSequence s, int start, int before, int count)
{
song = 2;
songsList2.clear();
for (HashMap<String, String> map : songsList)
{
if(map.get(KEY_TITLE).contains(s))
{
HashMap<String, String> map2 = new HashMap<String, String>();
// adding each child node to HashMap key => value
map2.put(KEY_ID, map.get(KEY_ID));
map2.put(KEY_TITLE, map.get(KEY_TITLE));
map2.put(KEY_ARTIST, map.get(KEY_ARTIST));
map2.put(KEY_DURATION, map.get(KEY_DURATION));
map2.put(KEY_THUMB_URL, map.get(KEY_THUMB_URL));
songsList2.add(map2);
adapter=new LazyAdapter(CustomizedListView.this, songsList2);
list.setAdapter(adapter);
}
}
adapter.notifyDataSetChanged();
}
Thanks!

Yes, the contains method is case sensitive. If you want to make it not so, you can either compile a regex pattern and use that instead, or simply make the value you search to lowercase and then check it, just as
if(map.get(KEY_TITLE).toLowerCase().contains(s)...
assuming that the char sequence is in the same case.
Edit:
As pointed out in the comments, to ensure a match where no assumption of the char sequence case is made, you would have to force the search phrase to the same case by using toLowerCase on it aswell
if(map.get(KEY_TITLE).toLowerCase().contains(s.toString().toLowerCase())...

First avoid using concrete classes when you can use interfaces. As far as I understand songsList is a list or arrays of HashMaps. Change the definition to List<Map<String, String>>. Now use TreeMap instead of HashMap but pass String.CASE_INSENSITIVE_ORDER comparator when creating the instance:
Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Now you do not need to change your code. you can put there "Yellow Submarine" and get either "yellow submarine" or "YELLOW SUBMARINE" or whatever. But the actual value stored in map remains "Yellow Submarine" (the value that you put), so if you iterate over the entries you get "correct" value.

Related

How To Access hash maps key when the key is an object

I cannot seem to figure out how to access the values of my hashmap
What I am basically trying to do is create a hashmap with an array as one of the values like json style.. If that makes sense?
So I want something like hash{key: value1, value2, value3, [number1,number2]}
and be able to access it like (pseudocode:) hash.get(3).get(1)
public class WebSearch {
readFile.ReadFile xfile = new readFile.ReadFile("inputgraph.txt");
HashMap webSearchHash = new HashMap();
ArrayList belongsTo = new ArrayList();
ArrayList keyphrase = new ArrayList();
public WebSearch() {
}
public void createGraph()
{
HashMap <Object, ArrayList<Integer> > outlinks = new HashMap <Object, ArrayList<Integer>>();
for (int i = 0; i < xfile.getNumberOfWebpages(); i++ )
{
keyphrase.add(i,xfile.getKeyPhrases(i));
outlinks.put(keyphrase.get(i), xfile.getOutLinks(i));
}
}
keyphrases is an ArrayList
this is my output of System.out.print(outlinks);
{[education, news, internet]=[0, 3], [power, news]=[1, 4], [computer, internet, device, ipod]=[2], [university, education]=[5]}
How would I go about getting say just this: [education, news, internet]=[0, 3]
I have tried:
outlinks.get(xfile.getKeyPhrases(i))
xfile.getKeyPhrases(0) would for example return [education, news, internet]
You can get the key set (Map.keySet()) of the map first; outlinks.keySet()
Then you can use these keys on your map to get your entries (values of the keys)
You haven't posted enough of the surrounding code for your question to be entirely clear, but look at the Javadocs for Map. You will probably get what you want by iterating over outlinks.values().
I recommend to use a customized object and use it inside your collections.
You may create a POJO/Bean class and overwrite the toString method with the details that you want, for instance the a iterate over items inside a array.
When you use it to print or display the toString method will be call.
The following link show you some ideas:
http://www.javapractices.com/topic/TopicAction.do?Id=55
http://en.wikipedia.org/wiki/Plain_Old_Java_Object
You can access the keys of any HashMap using Map.keySet() method.
Also note that java.util.HashMap is unordered. HashMap makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
You would like to relook at the structure of your HashMap, you are having ArrayList as your key.

HashMap with ArrayList key can not find it when Arraylist grows

Well my problem is that in some part of my code I use an arraylist as a key in a hashmap for example
ArrayList<Integer> array = new ArrayList<Integer>();
And then I put my array like a key in a hash map (I need it in this way I'm sure of that)
HashMap<ArrayList<Integer>, String> map = new HashMap<ArrayList<Integer>, String>();
map.put(array, "value1");
Here comes the problem: When I add some value to my array and then I try to recover the data using the same array then the hash map cant find it.
array.add(23);
String value = map.get(array);
At this time value is null instead of string "value1"
I was testing and I discovered that the hashCode changes when array list grows up and this is the central point of my problem, but I want to know how can I fix this.
Use an IdentityHashMap. Then that same array instance will always map to the same value, no matter how its contents (and therefore hash code) are changed.
You can't use a mutable object (that is, one whose hashCode changes) as the key of a HashMap. See if you can find something else to use as the key instead. It's somewhat unusual to map a collection to a string; the other way around is much more common.
Its a weird use case but if you must do it then you can sub class the array and override the hashCode method.
Its a bit of an add thing to try and do in my opinion.
I assume what you are trying to model is a variable length key made up of n integers, and assume that the hash of the ArrayList will be consistent, but I'm not sure that is the case.
I would suggest that you either subclass ArrayList and override the hash() & equals() methods, or wrap the HashMap in a key class.
I'm almost certain you would not want to do that. It's more likely you would want a Map<String, List<Integer>>. However, if you absolutely must do this, use a holder class:
public class ListHolder {
private List<Integer> list = new ArrayList<Integer>();
public List<Integer> getList() {return list;}
}
Map<ListHolder, String> map = new HashMap<ListHolder, String>;
The basic reason: When we use HashMap.put(k, v), it will digit k.hashCode() so that it can know where to put it.
And it also find the value by this number(k.hashCode());
You can see the ArrayList.hashCode() function and it is in the abstract class of AbstractList. Obviously, after we add some object, it will change the haseCode value. So we can not find the value use HashMap.get(K) and there is no element which hashCode is K.
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}

Adding items to empty List at specific locations in java

Is there any way I can make the below code work without commenting the 3rd line.
List<Integer> list = new ArrayList<Integer>();
list.add(0,0);
//list.add(1,null);
list.add(2,2);
I want to add items to list at specific locations. But if I don't change the index to Nth position I am not being able to add at Nth as told in this answer.
I can't use a map because I don't want to miss a value when the keys are same. Also adding null values to a list for large lists will be an overhead. When there is a collision I want the item to take the next position(nearest to where it should have been).
Is there any List implementation that shifts index before it tries to add the item?
Use something like a MultiMap if your only concern is not "missing a value" if the keys are the same.
I'm not sure how doing a shift/insert helps if I understand your problem statement--if the "key" is the index, inserting will lose the same information.
You can use Vector and call setSize to prepopulate with null elements.
However, your comment about the overhead of the nulls speaks to an associative container as the right solution.
This still smells like you should be using a Map. Why not use a Map<Integer, List<Integer>>?
something like,
private Map<Integer, List<Integer>> myMap = new HashMap<Integer, List<Integer>>();
public void addItem(int key, int value) {
List<Integer> list = myMap.get(key);
if (list == null) {
list = new ArrayList<Integer>();
myMap.put(key, list);
}
list.add(value);
}
public List<Integer> getItems(int key) {
return myMap.get(key);
}
Well, There are a couple of ways I would think to do this, if you are not adding items too frequently, then it might be a good idea to simply do a check to see if there is an item at that location before adding it.
if(list.get(X) == null)
{
list.add(X,Y);
}
Otherwise if you are going to be doing this too often...then I would recommend creating your own custom List class, and extending ArrayList or whatever you are using, and simply override the add method, to deal with collisions.

Java Hashtable problem

I am having some problem with java hashtable. Following is my hastable key and values
{corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
So if i want to access first tuple i have to pass key "corpus\2.txt" to get its value. If i pass value i can get it's key. But I want to make a function I pass like 1 2 3 4 etc. and get both key and value. Any idea?
2nd question:
Is it possible to store an index with key and value too?? Or is it possible to get index ( 0,1,2,3 etc. ) from existing hashtable?
Thanks !
For starters, I would use a HashMap, rather than the (now obsolete) HashTable. If you do that, then you can use Map.Entry to return a key/value pair (as per your first question).
You can't easily store an index with your key. You might want to create a special Key object thus:
public class Key {
private String name;
private int index;
....
}
with a suitable equals()/hashCode() implementation (as pointed out below in the comments) and use that as the key in your HashMap. You've have to perform a lookup using this key and thus construct one from your current String-based key, but I don't think that's a big deal.
There is no method in the API to get a specific entry from a Java hash table. You can access the collection of all entries with the entrySet method, and iterating over that you will get all the key-value pairs as Map.Entry objects.
Hash tables are completely unordered. They are just mappings from keys to values and do not have any definite indices. There is a specific order that the entries will be processed if you iterate over the entrySet result, but this might also change when you modify the hash table.
Take a look at LinkedHashMap, a map implementation that preserves input ordering.
Rather use a Map<Integer, ValueObject> wherein ValueObject is just a custom javabean class with two properties e.g. filename and description.
Basic kickoff example:
public class ValueObject {
private String filename;
private String description;
public ValueObject() {
// Always keep default constructor alive.
}
public ValueObject(String filename, String description) {
this.filename = filename;
this.description = description;
}
// Add/generate public getters and setters for filename and description.
}
which you can use as follows:
Map<Integer, ValueObject> map = new HashMap<Integer, ValueObject>();
map.put(1, new ValueObject("corpus1.txt", "elephant cow"));
map.put(2, new ValueObject("corpus2.txt", "cat sparrow"));
map.put(3, new ValueObject("corpus3.txt", "cow cat"));
map.put(4, new ValueObject("corpus4.txt", "elephant sparrow"));
ValueObject vo = map.get(1); // Returns VO with corpus1.txt and elephant cow.
There's no way to access a Map by index. However, if what you really want to do is access the key-value pairs in the map one by one, you can just do:
for (Map.Entry<String, List<String>> nameAndWords: hashmap) {
String name = nameAndWords.getKey();
List<String> words = nameAndWords.getValue();
// do your stuff here
}
If you actually need indexing, you can add an external order to the map by keeping the keys in a list, which must be updated when you edit the map:
HashMap<String, List<String>> wordsByCorpus;
List<String> corpusNames;
public void addCorpus(String name, List<String> words) {
List<String> oldValue = wordsByCorpus.put(name, words);
if (oldValue == null) corpusNames.add(name);
}
public void removeCorpus(String name) {
wordsByCorpus.remove(name);
corpusNames.remove(name);
}
public Map.Entry<String, List<String>> getCorpus(int i) {
String name = corpusNames.get(i);
List<String> words = wordsByCorpus.get(name);
return wordsByCorpus.new SimpleImmutableEntry(name, words); // 1.6 only!
}
You either want to use a LinkedHashMap which allows you to access values added to the map using the index of the order they were added in.
Or you want to use 2 HashMaps. One to index by the string value and the second one to convert the integer value into the string value key of the first map. Then simple to get key and value from index:
String key = mapByIntToStringKey.get(index);
V value = mapByStringKey.get(key);
// now have both key and value, no linear searching so should be fast
Thus your maps would contain:
mapByStringKey={corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
mapByIntToStringKey{2=corpus\2.txt, 4=corpus\4.txt, 1=corpus\1.txt}
although this is assuming that all your keys are not simply "corpus"+index+".txt".
If all keys are as above then if the indexes are not sparse then you could use a simple ArrayList (previously mentioned) and use get(index) which is fast (directly looks up in an array, can't get much faster than that), and then reconstruct the string key using the expression above.
If the indexes are sparse (i.e. some are missing, there are gaps) then just use the mapByIntToStringKey but replace with mapByIntToValue and reconstruct any string key you need using previous string expression.
The current high answer seems very odd to me, in that the suggestion is to key the map using the int index bit only of a compound key. Unless I'm reading it wrong, it means that you loose the ability to lookup values in the map using the string key alone or maybe just implies that you can always deduce the int index from the string key.

Searching through Collections in Java

I have a java properties file containing a key/value pair of country names and codes. I will load the contents of this file into a Collection like List or HashMap.
Then, I want users to be able to search for a country, e.g if they type 'Aus' in a textbox and click submit, then I want to search through the collection I have, containing a key/value pair of country codes/names (e.g AUS=>Australia), and return those countries which are found matching.
Is there any more efficient way of doing this, other than looping through the elements of the collection and using charAt()?
If performance is important, you can use a TreeSet or TreeMap to hold the country names, and do the following can be used to identify countries that start with a given string.
NavigableMap<String, String> countries = new TreeMap<String, String>();
countries.put("australia", "Australia");
...
String userText = ...
String tmp = userText.toLower();
List<String> hits = new ArrayList<String>();
Map.Entry<String, String> entry = countries.ceilingEntry(tmp);
while (entry != null && entry.getKey().startsWith(tmp)) {
hits.add(entry.getValue());
entry = map.higherEntry(entry.getKey());
}
// hits now contains all country names starting with the value of `userText`,
// ignoring differences in letter case.
This is O(logN) where N is the number of countries. By contrast a linear search of a collection is O(N)
Looping with String.contains() is the way unless you want to move in some heavy artillery like Lucene.
Short of indexing the collection via something like Lucene, then you'd have to manually check by looping through all of the elements. You could use startsWith as opposed to looping over the string:
String userText = ...
for (Map.Entry<String, String> entry : map) {
boolean entryMatches = entry.getKey().startsWith(userText);
...
Or alternatively use regular expressions:
Pattern pattern = Pattern.compile(userText);
for (Map.Entry<String, String> entry : map) {
boolean entryMatches = pattern.matcher(entry.getKey()).find();
...
Since the list is small enough to load into memory, sort it and then do a binary search, using the static method java.util.Collections.binarySearch(). This returns an index, and works regardless of whether the exact string is in the list or not (although if it's not it returns a negative number, so be sure to check that). Then, starting from that index, just iterative forward to find all the strings with that prefix. As a nice side-effect, the resulting output will be in alphabetical order.
To make the whole thing case insensitive, remember to convert to lowercase when loading the list and of course convert the prefix to lowercase before searching.

Categories

Resources