How to implement a Map with array list as keys - java

I have HashMap with ArrayList as key and value as Integer, how can I get value from specific key.
Map< List<Object>,Integer> propositionMap=new HashMap<List<Object>,Integer>();
my key are:[Brand, ID], [Launch, ID], [Model, ID], [Brand, UserModelNoMatch], [ProducerPrice, UserModelMatch], [ProducerPrice, ID]]
my values are:[3, 5, 4, 2, 1, 6]
In my program in several time in different place i need to find a specific value for the specific key. i do not want to use for loop evry time to get value.
how can i do that?

Putting aside that this is a bad idea (as described in the comments), you don't need to do anything special:
List<Object> list = new ArrayList<Object>();
// add objects to list
Map<List<Object>,Integer> propositionMap = new HashMap<List<Object>,Integer>();
propositionMap.put(list, 1);
Integer valueForList = propositionMap.get(list); // returns 1
You can get the same value when constructing a list independently:
List<Object> list2 = new ArrayList<Object>();
// add the same objects (by equals and by hashcode) to list2 as to list
Integer valueForList = propositionMap.get(list2); // returns 1
But you need to be careful not to change the list after you use it as a key in the map!
list.add(new Object());
Integer valueForList = propositionMap.get(list); // likely returns null
Again, it's very likely a bad idea.

Seeing as how you want the same behavior, I strongly recommend using an interface with classes.
public interface Proposition
{
public int getID();
}
public class Brand implements Proposition
{
private int id;
public Brand(int _id_)
{
this.id = _id_;
}
public int getID()
{
return this.id;
}
}
public class Launch implements Proposition
{
private int id;
public Launch(int _id_)
{
this.id = _id_;
}
public int getID()
{
return this.id;
}
}
public class ProducerPrice implements Proposition
{
private int id;
private int UserModelMatch;
public ProducerPrice(int _id_, int _UserModelMatch_)
{
this.id = _id_;
this.UserModelMatch = _UserModelMatch_;
}
public int getID()
{
return this.id;
}
public int getUserModelMatch()
{
return this.UserModelMatch;
}
}
And then using a hashmap for proposition objects
Map<Integer, Proposition> propositionMap = new HashMap<Integer, Proposition>();
Proposition newprop = new ProducerPrice(6, 1);
propositionMap.put(newprop.getID(), newprop);
Proposition someprop = propositionMap.get(6);
if (someprop instanceof ProducerPrice)
{
ProducerPrice myprodprice = (ProducerPrice)someprop;
// rest of logic here
}

You can get the value as usual way :
propositionMap.get(arrayListN)
until you modify the list itself after adding.

Related

Binary search Java list with key extractor

Say I have:
class Item {
int id;
int type;
}
I can do this:
List<Item> items;
Item itemToFind;
Comparator<Item> itemComparator;
Collections.binarySearch(items, itemToFind, itemComparator);
However, say that instead of the whole object, I'm only given a property of the object, say type for the above example. Assuming the list is sorted by that property, is there a standard method in Java or some established library to do something to this effect:
List<Item> items;
Function<Item, Integer> typeExtractor = Item::getType;
int typeToFind;
Comparator<Integer> typeComparator = Integer::compare;
binarySearch(items, typeExtractor, typeToFind, typeComparator);
without additional overhead (e.g. converting List<Item> to List<Integer> to call Collections.binarySearch on or similar)?
Your problem is that in a Collection<T> the binary search implementation of java allows to search only for items of type T. In order to search for another type which is a part of T, you can do the following:
Wrap the other type inside T, in your case this should look like this:
List<Item> items;
int typeToFind;
Item itemToFind = new Item(/* random value for id */ 0, typeToFind);
int index = binarySearch(items, itemToFind , (a, b) -> a.getType() - b.getType());
Some important notes to add here:
- the comparison of items should depend only and only on `type`, otherwise you may end up with some nasty bugs;
- the list of items should be sorted. The sorting should depend only and only on `type`(basically using the same comparator as before)
Create a new list from the initial list:
List<Items> items;
int typeToFind
int index = binarySearch(items.stream.map(item -> item.getType()).collect(Collectors.toList()), itemToFind);
As far as I know, the standard library for Java does not provide binary search implementation with a comparator for key equality. If these options does not satisfy you, probably you should search for a library or implement your own search.
The comparator still would be Comparator<Item>. What you would change is the implementation of the comparator to evaluate upon the type instead of the id.
Comparator<Item> comparator = new Comparator<Item>(){
public int compare(Item a, Item b)
{
return a.getType() - b.getType();
}
}
Item, would need to have the getter for type or the attribute made public. The same if using the id.
However, not sure how you suggest I would call
Collections.binarySearch
The usage doesn't change (what changes is how the comparison is done inside the comparator object):
Item itemToFind = new Item();
itemToFind.setType(typeToFind);
Collections.binarySearch(items, itemToFind, comparator );
After some thought on the subject:
An alternative to use an Item as a needle is to base the Comparator on an Interface that Item and the needle implement.
An interface to return int values:
public interface Intgettable{
public int getInt();
}
Item should have to implement this interface:
public class Item implements Intgettable{
private int id;
private int type;
public void setId(int id){
this.id = id;
}
public void setType(int type){
this.type = type;
}
public int getId(){
return id;
}
public int getType(){
return type;
}
public int getInt(){
return type;
}
}
The key to search will be an Intgettable which can be created:
1 - Using a class that extends Intgettable.
public static class MyItemKey implements Intgettable{
private int value;
public MyItemKey(int v){
this.value = v;
}
#Override
public int getInt(){
return value;
}
}
MyItemKey typeToFind = new MyItemKey(6);
2 - As an anonymous class inside the method.
Intgettable typeTofind = new Intgettable(){
private int value = 6;
public int getInt(){
return value;
}
};
3 - Or using the lambda version:
Intgettable typeTofind = ()->{return 6;};
The Comparator will be:
Comparator<Intgettable> comparator = new Comparator<Intgettable>(){
public int compare(Intgettable a, Intgettable b){
return a.getInt() - b.getInt();
}
};
And finally use it in the binary search:
Collections.binarySearch(items, typeToFind, comparator );

Multiple Field Collection Sort

I have a class Arraylist contains value
String word, String expandedword, double confidence, double support
I want to sort the arraylist based on the confidence, and then based on the support.
I have succeed sort the arraylist based on confidence, but i failed to make a new method to sort the arraylist based on the support
this is my code to sort it based on confidence
public class ExpandedTerm implements Comparable<ExpandedTerm> {
String word;
String expandedWord;
double support;
double confidence;
public ExpandedTerm (String word,String expandedWord, double confidence,double support){
this.word = word;
this.expandedWord = expandedWord;
this.support = support;
this.confidence = confidence;
}
public String getWord(){
return word;
}
public String expandedWord(){
return expandedWord;
}
public Double getSupport(){
return support;
}
public Double getConfidence(){
return confidence;
}
#Override
public int compareTo(ExpandedTerm conf) {
return new Double(this.confidence).compareTo(new Double(conf.confidence));
}
I failed to make another method like compareTo, to sort it based on the support value.
How to sort it first by the confidence, and then make another method to sort it by the support value?
User Comparator for this. As compaarble provide functionality to sort on single type basis.
here is link where you found when to use comparable and comapartor
http://iandjava.blogspot.in/2012/10/comparable-and-comparator.html
Use multiple comparartor
one for confidence
public class ConfidanceComparator implements Comparator<ExpandedTerm> {
#Override
public int compare(final ExpandedTerm o1, final ExpandedTerm o2) {
return new Double(o1.confidence).compareTo(new Double(o2.confidence));
}
}
one for support
public class SupportComparator implements Comparator<ExpandedTerm> {
#Override
public int compare(final ExpandedTerm o1, final ExpandedTerm o2) {
return new Double(o1.support).compareTo(new Double(o2.support));
}
}
and use Collections.sort(<List>, <comparator>) adn you will get the desired list.
THis is only required when you want to sort either on confidance basis or support basis.
But if you required then first sort on confidance basis and if confidance is equal then check for support basis. then comparable is sufficient and is
public int compareTo(ExpandedTerm conf) {
int compare = new Double(this.confidence).compareTo(new Double(conf.confidence));
if (compare == 0) {
compare = new Double(this.support).compareTo(new Double(conf.support));
}
return compare;
}
Try this code for your compareTo method:
#Override
public int compareTo(ExpandedTerm other) {
Double thisConfidence = new Double(getConfidence());
Double otherConfidence = new Double(other.getConfidence());
int compare = thisConfidence.compareTo(otherConfidence);
if (compare == 0) {
Double thisSupport = new Double(getSupport());
Double otherSupport = new Double(other.getSupport());
compare = thisSupport.compareTo(otherSupport);
}
return compare;
}
Basically only compare "support" if "confidence" is equal.
I saw your reply that you want to sort once and sort again except differently, so I'm assuming you want to add a custom Comparator when you sort. Is this what you're looking for?
public static void main(String[] args) {
ExpandedTerm term1 = new ExpandedTerm("a", "b", 1, 4);
ExpandedTerm term2 = new ExpandedTerm("c", "d", 3, 2);
List<ExpandedTerm> list = new ArrayList();
list.add(term1);
list.add(term2);
Collections.sort(list);
System.out.println(list);
Collections.sort(list, new Comparator<ExpandedTerm>() {
#Override
public int compare(ExpandedTerm o1, ExpandedTerm o2) {
return new Double(o2.confidence).compareTo(new Double(o1.confidence));
}
});
System.out.println(list);
}
Here's the output
[ExpandedTerm#2eeb3c84, ExpandedTerm#55d2162c]
[ExpandedTerm#55d2162c, ExpandedTerm#2eeb3c84]
Some other tips: make sure you implement the toString(), hashCode(), and equals() functions for your ExpandedTerm. These are essential for debugging and also for use in other Collections like HashMap, etc.

Write Java Comparator

I have created a Vector object to store data in Table object as Vector<Table>. Vector<Table> contains components as below.
[Vector<Record> records, String tableName, String keyColumnName, int recordCount, int columnCount]
I need to sort tableName in above Vector to my own order and return Vector<Table> with sorted tableNames for other processes.
I have wrote method as below.
private Vector<Table> orderTables(Vector<Table> loadTables) {
List<String> tableNames = new ArrayList<String>();
for (Table table : loadTables) {
String tblName = table.getTableName();
tableNames.add(tblName);
}
Collections.sort(tableNames, new MyComparable());
return null;
}
But I have no idea about how to write Comparator to this. My own sort order is stored in .properties file. I can read it and get value. But I have no idea about how to compare it.
How could I do it?
Before clarification
You need to write a Comparator for Table objects that delegates to the tableName's comparator:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return one.getTableName().compareTo(two.getTableName());
}
}
Note that this will consider Tables that have the same name to be equal. This can mess things up if you put these tables in a HashMap or HashSet. To avoid this, you can detect this case and return one.hashCode() - two.hashCode() if the table names are the same.
Guava's ComparisonChain is a convenient way to write such multi-stage comparisons:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return ComparisonChain.start()
.compare(one.getTableName(), two.getTableName())
.compare(one.hashCode(), two.hashCode())
.result();
}
}
After clarification
Okay, the question is to impose a predefined sorting order rather than sorting the Tables by name. In that case, you need to make a Comparator that is aware of the ordering defined in the .properties file.
One way to achieve this is to initialize a mapping of table names to sorting order indices, and refer that mapping during the comparison. Given the property value:
SORT_ORDER = SALES,SALE_PRODUCTS,EXPENSES,EXPENSES_ITEMS
The mapping should look like:
{
SALES: 0,
SALE_PRODUCTS: 1,
EXPENSES: 2,
EXPENSES_ITEMS: 3
}
Here's what the comparator would look like:
private static class PredefinedOrderComparator implements Comparator<Table> {
public PredefinedOrderComparator() {
// Initialize orderIndex here
}
private final Map<String, Integer> orderIndex;
#Override public int compare(Table one, Table two) {
return orderIndex.get(one.getTableName()) - orderIndex.get(two.getTableName());
}
}
To populate orderIndex from the property value, you need to:
Get the comma-separated list using getProperty() as you mentioned
Split that value on comma (I recommend using Guava's Splitter, but String.split or others will work too)
Initialize a new HashMap<String, Integer> and an int index = 0
Iterate through the split tokens, map the current token to index and increment index
Note the implicit assumption that none of the table names have a comma in it.
public class MyComparable implements Comparator<Table>{
#Override
public int compare(Table table1, Table table2) {
return (table1.getTableName().compareTo(table2.getTableName());
}
}
make sure that you have overridden the hashcode and equals in Table class to achieve this.
I wrote you a very simple example on how to work with a Comparator. If you create a class called Main, copy paste below contents in it, compile and run it, you can see what's going on.
A comparator just needs to implement an interface. For this it needs to implement one method (public int compare(T arg0, T arg1). There you specify how a collection will get sorted; in this case according to the alfabet.
I hope this helps you.
import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println("Start\n");
List<Item> items = new ArrayList<Item>();
for(String s : new String[]{"mzeaez", "xcxv", "hjkhk", "azasq", "iopiop"}) {
items.add(createItem(s));
}
System.out.println("Items before sort:");
System.out.println(Item.toString(items));
Collections.sort(items, new ItemComparator());
System.out.println("Items after sort:");
System.out.println(Item.toString(items));
System.out.println("End");
}
private static Item createItem(String s) {
Item item = new Item();
item.setS(s);
return item;
}
}
class Item {
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
#Override
public String toString() {
return "Item: " + s;
}
public static String toString(Collection<Item> items) {
String s = "";
for(Item item : items) {
s += item + "\n";
}
return s;
}
}
class ItemComparator implements Comparator<Item> {
#Override
public int compare(Item item1, Item item2) {
return item1.getS().compareTo(item2.getS());
}
}

java - return two results in one function call? [duplicate]

This question already has answers here:
How to return multiple objects from a Java method?
(25 answers)
Closed 9 years ago.
I'm trying to do something like this:
public void <String,int> getItem
{
return <"Jen",23>;
}
I know I can use a custom class, but how I would I return two results in one function call.
1 - Is the above template function possible in java, and how would by caller get part 1 of it and part 2 later.
2 - Can I do it using an associative array like in actionscript?
3 - Can I do it using a hashmap of some sort?
4 - What are other possible ways are there
I attempted all three ways, but one way or another syntax is hitting me. So if anyone can give clear examples
Java functions always return a single value, so your only option is to return a "collection" object which contains multiple values, such as an Array or a proper Collection. For example:
public Object[] getItem() { return new Object[] { "Jen", 23 }; }
public Collection<Object> { return Arrays.asList("Jen", 23); }
Although, a typical pattern in Java is to return a custom type which encapsulates your values, e.g.:
public class NameAge {
public final String name;
public final int age;
public NameAge(String name, int age) {
this.name = name;
this.age = age;
}
}
// ...
public NameAge getItem() { return new NameAge("Jen", 23); }
Or more generally:
public class Pair<X, Y> {
public final X x;
public final Y y;
public Pair(X x, Y y) {
this.x = x;
this.y = y;
}
}
// ...
public Pair<String,Integer> getItem() {
return new Pair<String,Integer>("Jen", 23);
}
Of course, there are serious implications regarding hashing (equality and hash code) if you want to use these custom types as hash keys.
I like using generics! Create your own class and return an instance of it:
public class Tuple<T,V>
{
public T item1;
public V item2;
public Tuple(T i1, V i2)
{
item1 = i1;
item2 = i2;
}
}
Then you create your method:
public Tuple<String, int> getItem()
{
return new Tuple<String, int>("Jen", 23);
}
Java does not allow for multiple return statements. The best practice I believe is to create a custom object. What you have here suggests some sort of Person class, a la
public class Person {
int Age;
String Name;
}
Returning an object will make it more intuitive what you are doing as well.
You can return a Bundle.
public Bundle getItem(){
Bundle theBundle = new Bundle();
theBundle.putString("name","Jen");
theBundle.putInt("age",23);
return theBundle;
}
Usually, if you need to return two values from one function - it's a code smell. Try to refactor your code so that every function always return just one value. Keep in mind that no return value (void) is also a code smell, but less critical.
The proper way would be to create a class for your return set:
public class ReturnSet {
private String str;
private int num;
public ReturnSet(String _str, int _num) {
str = _str;
num = _num;
}
//add getters and setters
...
}
Then your function would look like
public ReturnSet getItem() {
...
return new ReturnSet(strValue, intValue);
}
Of course, you can fudge things by having your function return an array of Object, but this would be a rather bad code:
public Object[] getItem() {
Object[] result;
//allocate it, get data;
...
result[1] = strValue;
relult[2] = new Integer(intValue);
return result;
}
You can even return a hashmap with one element in it:
public Map getItem() {
Map result;
//allocate it, say as hashmap, get data;
...
result.put(strValue, new Integer(intValue));
return result;
}
Then in the caller, the key of the map would be the first part and the value would be the second.
While there are may be many ways of doing things like that, the first one is the right approach.
If a method returns something, then its return type must be this something:
public MyCustomObject getItem();
or
public Object[] getItem():
or anything else wher you can store the results.
But Java is a statically typed OO language. A custom class is the way to go.
You can also return one value the regular way and other(s) by using a "return" parameter:
class C {
Type2 value; // omitted getter and setter for brevity
}
Type1 f1(C returnParameter, String otherParameters...)
{
// function body here
returnParameter.value=returnValue2; // store the second result
return returnValue1; // return the first result
}
// usage
Type1 result1;
Type2 result2;
C helper = new C();
result1=f1(helper, "foo", "bar");
result2=helper.value;
For more results either use several "helper" objects or one that can hold several values.
I am myself looking for a most elegant solution (in my case one return type is a Collection and the other is an integer number-any variant of it is OK).

Java - Can a hashmap have 4 generic parameters instead of 2?

This may be difficult to explain, but here goes:
I want to store 3 integers and a String to a Hashmap, so I can retrieve data from the map, but it turns out that hashmaps only allow 2 generic parameters instead of 4.
For example: HashMap <String> <Integer> <Integer> <Integer> (what I want to do)
but you can only use 2 parameters, as it seems: HashMap <String> <Integer>.
My best guess is that my idea cannot be done, if so please list the alternatives to handling something like this.
Make a new class which holds 3 Integer or maybe int.
class Triple {
Integer i;
Integer j;
Integer k;
Triple(Integer i,Integer j, Integer k) {
this.i = i;
this.j = j;
this.k = k;
}
}
and put this class to a map with the String.
HashMap map = new HashMap<String, Triple>();
map.put("keyString", new Triple(new Integer(1),new Integer(2),new Integer(3)));
You should create an object to hold that data, and then store it like this: HashMap<String, MyObject>.
Also, these aren't constructors. They are generics.
You don't need a hashmap to store 4 values. To store 3 integers and 1 String:
public class MyClass {
int a,b,c;
String d;
}
You can get the answer indirectly, like composing the three integer to one character string,
int val1=1;
int val2=2;
int val3=3;
Map<String,String> test = new HashMap<String,String>();
test.put("key1", val1+"_"+val2+"_"+val3);
when you wan to get the values, int[] rst = test.get("key1).split("_");
Then you can access your integer values.
It seems to me that you are trying to store two different types of things as values in the hash map. There is no problem in doing this. Just create the hash map with the default constructor, and then just use Object as the value type. so new HashMap<String, Object>()
You can use a HashMap< TypeOfYourKey, Object > to store arbitrary objects.
I struggled with this same issue. I ended up creating a hashmap of a custom class. This fully worked, and allowed me to put whatever attributes I wanted in my class, and pull out those attributes for any item programmatically. Full example below.
public class Test1 {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addview);
//create the data mapping
HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
hm.put(1, new myClass("Car", "Small", 3000));
hm.put(2, new myClass("Truck", "Large", 4000));
hm.put(3, new myClass("Motorcycle", "Small", 1000));
//pull the datastring back for a specific item.
//also can edit the data using the set methods. this just shows getting it for display.
myClass test1 = hm.get(1);
String testitem = test1.getItem();
int testprice = test1.getPrice();
Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}
class myClass{
private String item;
private String type;
private int price;
public myClass(String itm, String ty, int pr){
this.item = itm;
this.price = pr;
this.type = ty;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getType() {
return item;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}

Categories