how to get a linkedhashmap value using index? - java

i'm new to java.. i've made a linked hashmap like :
Map<String, Double> MonthlyCPIMenu = new LinkedHashMap<String, Double>();
MonthlyCPIMenu.put("1394/10", 0.0);
MonthlyCPIMenu.put("1394/09", 231.6);
MonthlyCPIMenu.put("1394/08", 228.7);
MonthlyCPIMenu.put("1394/07", 227.0);
MonthlyCPIMenu.put("1394/06", 225.7);
I know how to find each item's index using (for example):
String duemonth="1394/08";
int indexduemonth = new ArrayList<String>(MonthlyCPIMenu.keySet()).indexOf(duemonth);
but I don't know how to find the value using index. (I know how to get the value using key but in this case i should use index for some reason)

A crude way to do it would be
new ArrayList<String>(MonthlyCPIMenu.keySet()).get(index);
but LinkedHashMap generally doesn't support efficient indexed retrieval, and it doesn't provide any API for the purpose. The best algorithm to do it is just to take MonthlyCPIMenu.keySet().iterator(), call next() index times, and then return the result of one final next():
<K, V> K getKey(LinkedHashMap<K, V> map, int index) {
Iterator<K> itr = map.keySet().iterator();
for (int i = 0; i < index; i++) {
itr.next();
}
return itr.next();
}

First, do you have a specific reason you are using a LinkedHashMap? Generally speaking, iterating over keys is cheap and lookups are 0(1). Why does order of the values matter?
You can retrieve values from a map using the get(key) method.
Map.get(key);
You can protect against nulls with:
Map.get(key) != null ? Map.get(key) : "";
This will return the value if the key is found, else return an empty string. You can replace the empty string with whatever you want.

If you are set on getting the value then use the List interface and create your own type
public class MyValue {
String date;
String value;
public MyValue(String d, String v) {
this.date = d;
this.value = v;
}
public String getDate() {
return date;
}
public String getValue() {
return value;
}
}
Then use the List interface:
List<MyValue> list = new ArrayList<>();
// put all you values in the list
// get the values out by index in the list

Related

Most efficient way to retrieve key from value in a Hashmap without using BiMap

I'm counting words in a file and i've loaded the words and their respective counts into a hash map. I've sorted the values and use this to retrieve my key:
public static String getKey(TObjectIntHashMap<String> hash, int value){
for(String s: hash.keySet()){
if(value == hash.get(s)){
key = s;
hash.remove(key);
return key;
}
}
I know this is a pretty ugly way to do it, but it's the only way I can seem to get to work. I'm completely aware of the existence of bimaps, but would prefer not to use one. Any ideas?
A slightly more efficient way to do this would be to use an iterator, since this avoids having to do a separate lookup of the key and value:
public static String getKey(TObjectIntHashMap<String> hash, int value){
TObjectIntIterator<String> iterator = hash.iterator();
while (iterator.hasNext()) {
iterator.advance();
if (iterator.value() == value) {
key = iterator.key();
iterator.remove();
return key;
}
}
}
The best way to do this, is using a Multiset from guava collections. This is simple code:
//create multiset
Multiset<String> multiset = HashMultiset.create();
//add some strings
multiset.add("a");
multiset.add("a");
multiset.add("b");
//sort and print
System.out.println(Multisets.copyHighestCountFirst(multiset).entrySet();
More about Multiset, you can find here:
https://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset

Return the size of an ArrayList that is a value in a HashMap

I am working on project that is a spam filter for an email client.
public MailServer()
{
mailMap = new HashMap<String,ArrayList<MailItem>>();
}
I was instructed to use a HashMap to store the recipients and ArrayLists to hold their mailItems. The next method is to count and return the mailItems for a specific recipient.
public int howManyMailItems(String who)
{
int count = 0;
for(MailItem item : mailMap) {
if(item.getTo().equals(who)) {
count++;
}
}
return count;
}
Edit
I'm working in BlueJ and when I try to compile the class it highlights mailMap in the 4th line and says
"for-each loop not appicable"
public int howManyMailItems(String who)
{
int count = 0;
for(MailItem item : mailMap.keySet()) {
if(item.getTo().equals(who)) {
count++;
}
}
return count;
}
When I try a keySet it says incompatible types.
A Map does not implement the Iterable interface. This is why you get the "for-each loop not appicable" error. You have a choice of iterating over the map's
entrySet() — a Set<Map.Entry<K,V>> (where K is the key type and V is the value type of the map);
keySet() — a Set<K>; or
values() — a Collection<V>.
In general, you would want to do something like this:
public int howManyMailItems(String who)
{
int count = 0;
for(Map.Entry<String,ArrayList<MailItem>> entry : mailMap.entrySet()) {
String key = entry.getKey();
ArrayList<MailItem> array = entry.getValue();
// process key and array value
}
return count;
}
It's hard to tell exactly what logic you are using to count. If you only need the arrays (and are ignoring the keys to your map), then you can use:
public int howManyMailItems(String who)
{
int count = 0;
for(ArrayList<MailItem> array : mailMap.values()) {
for (MailItem item : array) {
if (item.getTo().equals(who)) {
count++;
}
}
}
return count;
}
P.S. It's generally considered good practice to declare generic parameter types using interfaces rather than concrete types. For instance, your map could be declared:
Map<String, List<MailItem>>
rather than
Map<String, ArrayList<MailItem>>
(You would have to modify the type used in the iteration loop accordingly.) You can still put instances of ArrayList into the map, but you could also change your mind and put other kinds of List. (For instance, you could then put unmodifiable lists resulting from calls to Collections.unmodifiableList(...).)
public int howManyMailItems(String who) {
return mailMap.get(who).size();
}
You're not mentioning any errors, so it's tough to know what's wrong, but usually you iterate through a Map's Key Set, obtained via keySet(), or through its values obtained via values().
i.e.,
for(String key : mailMap.keySet()) {
List<MainItem> itemList = mailMap.get(key);
count += itemList.size(); // ??? not sure if this is what you want??
// ... etc..
}
As you have HashMap<String,ArrayList<MailItem>>. The key is type of String and value is ArrayList<MailItem>. The reason of your error is that you fetch the List and try to assign it to MaiItem.
public int howManyMailItems(String who)
{
int count = 0;
if(who == null) { //Check the input before operate
return count;
}
for(Iterable<MailItem> iterable : mailMap.values()) { //Interface instead of Class
for (MailItem item : iterable) {
if (item == null) { //It is possible that item can be null
continue;
}
if (who.equals(item.getTo())) { //It is possible that To can be null
count++;
}
}
}
return count;
}
Why to use Iterable instead of ArrayList in for-each loop ?
The advantage of that solution is that, we do not have to change the code we decide to use another Collection for our storage.
Why Iterable not Collection ?
In this case we perform only read operation, so this is the required minimum to solve the task. The advantage of this is greater code flexibility.

Ordered insertion in linkedHashSet, any performant way ?

So I have a LinkedHashSet , with values say a1, a2, , b, c1, c2
I want to replace, b with x , such that the order of x should be same as order of b.
One obvious way would be
private LinkedHashSet<String> orderedSubstitution(final Set<String> originalOrderedSet, final String oldItem,
final String newItem) {
final LinkedHashSet<String> newOrderedSet = new LinkedHashSet<String>();
// Things we do to maintain order in a linkedHashSet
for (final String stringItem : originalOrderedSet) {
if (stringItem.equals(oldItem)) {
newOrderedSet.add(newItem);
} else {
newOrderedSet.add(stringItem);
}
}
return newOrderedSet;
}
not only this is O(n) i also feel this is not the fastest way. Any better solution ?
NOTE : I HAVE TO use linkedHashMap.
One way to do it would be to use a subclass of LinkedHashSet that has the replacement built in, e.g.:
public class ReplacingLinkedHashSet extends LinkedHashSet<String> {
private final String what;
private final String with;
public ReplacingLinkedHashSet(String what, String with) {
this.what = what;
this.with = with;
}
#Override
public Iterator<String> iterator() {
final Iterator<String> iterator = super.iterator();
return new Iterator<String>() {
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public String next() {
String next = iterator.next();
return what.equals(next) ? with : next;
}
#Override
public void remove() {
iterator.remove();
}
};
}
}
But that means the replacement would have to be known before you fill the Set.
(Of course you could easily turn this <String> version into a generic one.
Responding to comments:
OK, then there is no way to solve it without a full iteration. You could however just leave the LinkedHashSet untouched and decorate the iterator when retrieving the values.
Create a structure Map
Insert all the string with < String, OrderOfTheString>
Do the insertion of the new String by adding a small Delta after the current string's OrderOfTheString.
Convert Map to LikedHashSet
I know it is complicated but it is definately better when we have linked hash Map of ~1000000 elements and there are about 1000 elements to be inserted.

Is there a Java Class similar to ArrayList that can do this?

I have been running into this problem sometimes when programming.
Imagine I have a table of data with two columns. The first column has strings, the second column has integers.
I want to be able to store each row of the table into a dynamic array. So each element of the array needs to hold a string and an integer.
Previously, I have been accomplishing this by just splitting each column of the table into two separate ArrayLists and then when I want to add a row, I would call the add() method once on each ArrayList. To remove, I would call the remove(index) method once on each ArrayList at the same index.
But isn't there a better way? I know there are classes like HashMap but they don't allow duplicate keys. I am looking for something that allows duplicate entries.
I know that it's possible to do something like this:
ArrayList<Object[]> myArray = new ArrayList<Object[]>();
myArray.add(new Object[]{"string", 123});
I don't really want to have to cast into String and Integer every time I get an element out of the array but maybe this is the only way without creating my own? This looks more confusing to me and I'd prefer using two ArrayLists.
So is there any Java object like ArrayList where it would work like this:
ArrayList<String, Integer> myArray = new ArrayList<String, Integer>();
myArray.add("string", 123);
Just create simple POJO class to hold row data. Don't forget about equals and hashCode and prefer immutable solution (without setters):
public class Pair {
private String key;
private Integer value;
public Pair(String key, Integer value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Integer getValue() {
return value;
}
// autogenerated
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Pair)) return false;
Pair pair = (Pair) o;
if (key != null ? !key.equals(pair.key) : pair.key != null) return false;
if (value != null ? !value.equals(pair.value) : pair.value != null) return false;
return true;
}
#Override
public int hashCode() {
int result = key != null ? key.hashCode() : 0;
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
}
Usage:
List<Pair> list = new ArrayList<Pair>();
list.add(new Pair("string", 123));
Note: in other languages there are build-in solutions for it like case-classes and tuples in Scala.
Create a Row class that holds the data.
package com.stackoverflow;
import java.util.ArrayList;
import java.util.List;
/**
* #author maba, 2012-10-10
*/
public class Row {
private int intValue;
private String stringValue;
public Row(String stringValue, int intValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
public int getIntValue() {
return intValue;
}
public String getStringValue() {
return stringValue;
}
public static void main(String[] args) {
List<Row> rows = new ArrayList<Row>();
rows.add(new Row("string", 123));
}
}
You can create very simple object, like :
public class Row{
private String strVal;
private Integer intVal;
public Row(String s, Integer i){
strVal = s;
intVal = i;
}
//getters and setters
}
Then use it as follows :
ArrayList<Row> myArray = new ArrayList<Row>();
myArray.add(new Row("string", 123));
Map is the option if you are sure that any one value among integer or string is unique. Then you can put that unique value as a key. If it is not true for your case, creating a simple POJO is best option for you. Infact, if in future, there a chance to come more values (columns) per row then also using a POJO will be less time consuming. You can define POJO like;
public class Data {
private int intValue;
private String strValue;
public int getIntValue() {
return intValue;
}
public void setIntValue(int newInt) {
this.intValue = newInt;
}
public String getStrValue() {
return strValue;
}
public void setStrValue(String newStr) {
this.strValue = newStr;
}
And in the class you can use it like;
ArrayList<Data> dataList = new ArrayList<Data>();
Data data = new Data();
data.setIntValue(123);
data.setStrValue("string");
dataList.add(data);
You should create a class (e.g. Foo) that contains an int and a String.
Then you can create an ArrayList of Foo objects.
List<Foo> fooList = new ArrayList<Foo>();
This is called a map my friend. It is similar to a dictionary in .net
http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
HashMap my be the class you are looking for assuming "string" going to different for different values. Here is documentation on HashMap
Example:
HashMap<String, Integer> tempMap = new HashMap<String, Integer>();
tempMap.put("string", 124);
If you need to add more than one value, you may create HashMap<String, ArrayList> like that.
you can use google collection library Guava there is a Map called Multimap. It is collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.
Use Map to solve this problem:
Map<String, Integer> map = new HashMap<String, Integer>();
Eg:
map.put("string", 123);

How to use indexOf on a List containing HashMap with multiple key/value pairs

I have a List containing HashMaps. Each HashMap in the list might have multiple key/value pairs. I want to indexOf on the list to find out the index of the element where the passed in HashMap is. However, the problem is that equals method of HashMap looks at all the entire entrySet while comparing. Which is not what I want.
Example:
List<HashMap> benefit = new ArrayList<HashMap>();
HashMap map1 = new HashMap();
map1.put("number", "1");
benefit.add(map1);
HashMap map2 = new HashMap();
map2.put("number", "2");
map2.put("somethingelse", "blahblah"); //1
benefit.add(map2);
HashMap find = new HashMap();
find.put("number", "2");
int index = benefit.indexOf(find);
if (index >= 0)
System.out.println(benefit.get(index).get("number"));
The above code does not print anything because of line with //1.
What do I have to do so that the above code actually prints 2?
Is there a way to implement comparable on the list so that I can define
my own?
I think you're looking for retainAll(), so you can compare only the elements you're interested in:
int index = myIndexOf(benefit, find);
...
static int myIndexOf(List<HashMap> benefit, Map find) {
int i = 0;
for (Map map : benefit) {
Map tmp = new HashMap(map);
tmp.keySet().retainAll(find.keySet());
if (tmp.equals(find)) {
return i;
}
i++;
}
return -1;
}
It's possible, of course, to declare your own subclass of List that overrides the indexOf method with this behaviour. However, I don't think that's a good idea. It would violate the contract of the indexOf method:
returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i)))
This would be confusing to someone else maintaining the code. You might then think that you could subclass HashMap to redefine equals, but that would violate the symmetry property of Object.equals().
The way you are trying to achieve your goal is wrong. The indexOf method works exactly as it should in this case. It is trying to find an exact match, not a partial one.
What you are trying to do, if I get it correctly, is to find a map in your list of maps that contains a specific entry. In this case, you should manually perform this search, by going through all the maps, calling containsKey (), and then comparing the value you are expecting to find with the value associated with the key.
The other way would be to create a proxy class around your List, and add a new method findMapWithEntry (String key, String value), which would perform this seach for you (the same search I described above).
Why not change the way you search?
List<Map> matchingBenefits = new ArrayList<Map>();
for (Map m : benefit) {
if (m.containsKey("number") && m.get("number").equals("2"))
matchingBenefits.add(m);
}
for (Map m : matchingBenefits) {
System.out.println(m.get("number"));
}
You can always override the indexOf method. Looking at the source for ArrayList:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
So it's not a very complex search algorithm at all. You may look at something like:
List benefit = new ArrayList(){
public int indexOf(Object o){
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
else {
for (int i = 0; i < size; i++) //traverse the hashmaps
Object key = ((HashMap)o).keySet().get(0); //assuming one pair
Object val = ((HashMap)o).valueSet().get(0);
if (
((HashMap)elementData[i]).containsKey(key) &&
((HashMap)elementData[i]).get(key).equals(val))
return i;
}
return -1;
};
My advice would be to consider a different data structure, perhaps writing your own one for it.
Given that you cannot change the design, would writing your own find method help?
The code below should work if I understood what you're trying to do and it runs in O(n)
public static String find(List<HashMap<String,String>> listMap, String key, String value) {
for(int i = 0; i < listMap.size(); i++)
if(listMap.get(i).get(key).equals(value))
return value;
return null;
}

Categories