views:

422

answers:

9

I'm having a bit of a hard time. Essentially I need a data structure that would work a bit like a database. I need to be able to have multiple bits of data for each key and have the possibility of having multiple keys with the same name. Then I need to be able to search that data structure and pull the correct keyword and check it against other possible data. Here is an example:

Keys   |   Name   |  Price

Airplane | Boeing | 10000
Airplane | LearJet | 4000
Airplane | Airbus | 20000
Car | Honda | 500
Car | Ford | 450
Car | Chevy | 600

So I need to be able to specifically be able to search for Airplanes and Airplanes that are Boeing's. For a lot of reasons I cannot use an actual database, it'd be complete overkill, since I don't have many records, but I do need to be able to pull these values. I found a multimap implementation in Java but it didn't allow me to insert multiple keys with the same name nor did it allow me to do search not only keys but keys with a corresponding value.

Anyone have an idea of how this might be implemented? Thanks

Edit: Okay I looked over all the answers. I for some reason just cannot understand any situation where you need keys to be unique but you are using maps. There are many answers that feature this solution and I take all fault for not being able to understand them. Ultimately I needed to have multiple unique keys and I know these solutions were workaround for that but I just couldn't make sense of it.

While it's far from being a perfect solution, I used Apache's MultiKey Class and since I only need to pull one possible value it works okay. I appreciate everyone's effort unfortunately I just couldn't get it work otherwise. Sorry

A: 

In that case, why not just use a java.util.List.

Suraj Chandran
+1  A: 

Why not a Set<Entry> where

public class Entry {
   String key;
   List<Item>  items;
}
public class Item {
    String name;
    int  price;
}
using that how would I search for items?
John Baker
With a list, you'll need to iterate over the items. That should be ok if the size is reasonably small (and it is O(n)). Otherwise, items can be a HashMap<String, Item> (with item name as key) and you have O(1); if going down that road, you may simply do away with Item and store name as key, and price as value.
yeah it looks like ultimately I'm going to have to write something to loop through multiple keys basically.
John Baker
A: 

You could use Map of Maps.

fastcodejava
I'm having a hard time conceiving of how that work would. Like how I could search both items
John Baker
+1  A: 

You need a nested Map. Here's a kickoff example:

Map<String, Map<String, Integer>> vehicles = new HashMap<String, Map<String,Integer>>();
Map<String, Integer> airplanes = new HashMap<String, Integer>();
vehicles.put("Airplane", airplanes);
airplanes.put("Boeing", 10000);
airplanes.put("LearJet", 4000);
airplanes.put("Airbus", 20000);
Map<String, Integer> cars = new HashMap<String, Integer>();
vehicles.put("Car", cars);
cars.put("Honda", 500);
cars.put("Ford", 450);
cars.put("Chevy", 600);

// To get price of Airplane - Airbus, just do:
Integer price = vehicles.get("Airplane").get("Airbus");
BalusC
I'll have to think about this solution since all my keys will be added dynamically and I will need multiple ones with the same name.
John Baker
+2  A: 

Why not use MultiKey from Apache Commons collections

http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/keyvalue/MultiKey.html

// populate map with data mapping key+name to price
Map map = new HashMap();
MultiKey multiKey = new MultiKey(key, name);
map.put(multiKey, price);

// later retireve the price
MultiKey multiKey = new MultiKey(key, name);
<Number> price = (String) map.get(price);
Vinodh Ramasubramanian
Hmm, I like this solution. I don't see how it's going to allow for access to multiple values though.
John Baker
I see the problem. I would tend to think in terms of PredicatedSortedMap but not sure if it would be easy to write a predicate to compare MultiKey objects.
Vinodh Ramasubramanian
A: 

You could certainly do this using Java's Collections, but this is really, really a task for a database.

Have you considered using an embedded databases? They allow you all the luxury of a DBMS without actually requiring one (they're just a library). Look e.g. at SQLite, or HSQLDb.

sleske
I could not disagree more vehemently. Like I said, I am going to have very few items in this table. To go through all that work of getting a database set up just for this minor thing? I think that's insane. Like killing a bird with a nuclear weapon. If you were doing tons of this stuff in your app, yeah I could see it, but it'd really have to be a lot to want to deal with all that
John Baker
A: 

Why not just use an embedded DB like H2. You can then execute your searches in SQL using some simple wrapper like SimpleJDBCTemplate in Spring. Alternatively you could create an ORM mapping for your objects and use HQL or search by example on your mapped objects.

Jherico
Well because it'd be major overkill. Why hassle with embedding a DB in your app when you are only going to use this function with very small sets of data. That's a lot of hassle for very little return. In this case it's not a web based app at all so Spring is out of the question.
John Baker
Spring is for IoC, not webapps specifically. I only suggested it because Spring-JDBC contains wrappers that make the use of a JDBC connection much simpler, by encapsulating a lot of the boilerplate code. If you don't like the idea of an embedded memory only DB, then you might research using a map with a List<String> as a key instead of String.
Jherico
Yeah, I do understand that Spring is for IoC, it's just too much overhead. This program is so small, to have to deal with all that is such a headache. I have found a workable solution at this point. I ended up using a Stack rather than a list, which eliminated my having to search through anything.
John Baker
A: 

the element in your hashmap could be an arraylist or another hashmap. that way one key maps to multiple integers. to search you would lookup the first key, then lookup the second key in the result. Check out BalusC's excellent example. Per your comment, dynamic insertion (if it doesn't know when the key was already added) would be something like:

Map<String,Integer> x = m.get("vehicle");
if (x == null) {
  x = new HashMap<String,Integer>();
  m.put("vehicle", x);
}
x.put("mfg", 20000);

a KeyPathMap class could be created that returns a map when you request it (getMap("vehicle")) and returns a value when you request a path that contains one (get({"vehicle", "mfg", "key 3", "key 4", "key 5"})), similar to a filetree.

another way is to make your key contain both strings. the key could be a simple concatenation ("Vehicle:Manufacturer") or a List as below:

List<String> k = Arrays.asList("vehicle", "manufacturer");
map.put(k, 10000);
...
map.get(k);

you could also use a custom key object with 2 fields that hashes based on the concatenation of the 2 (done by overriding hashCode and equals; your object can just delegate to internalString.hashCode and internalString.equals).

[moved from comments]

jspcal
A: 

Another multikey implementation could be found in Google's Collection Framework. Take a look at the javadoc. It is Apache V2 licensed, also.

dz