views:

3191

answers:

9

I want to create a HashMap in java for users with preferences. This would be easy to do in a database, but unfortunately I can't use a database. What I need is a way to find a user by name in the HashMap, and to find all the users with a certain interest (e.g. golf). If I delete a user, then all their interests should be deleted.

Anyone know a nice way to make this data structure?

+11  A: 

I would suggest you create your own data structure for holding the information. Inside that class you could have two HashMaps storing the relevant information. Then write your own methods to insert and delete a user.

This way you have control over the insert/delete-operations while being able to query each attribute separately.

Benedikt Eger
+4  A: 

Simplest solution is to use a Commons Collection MultiKeyMap even if it is lacking generics.

...Check this thread too genericized-commons-collection

KarlP
+2  A: 

I would implement the following

HashMap which include the user as key and the value could be any object which includs the userpreferences. The user preferences would include a list of interest for example.

And an additional HashMap with an interest as key and a list of users who are interested in this.

When you delet a user, you can get all the interest he has and delete the user name from the interest HashMap list. When the interest HashMap list is empty you can delet the interest from the HashMap.

Take care, when 2 or more users have the same interest. You can not delet the interest when only one user is deleted.

The downside is, that you will have redundant informations.

Markus Lausberg
+1  A: 

Just put the users in an ArrayList, and walk over it till you found the one(s) you need. Give each user a set of interests. Once you get enough users that it takes too long, sort them.

Once that takes too long, take a look at the distribution of interests. If you have a low number of different ones, store them in a bitmap. If you have a limited set of combinations of interests, store them separately and give a user one of these.

Start simple, computers are fast. But hide the implementation, so you can change it.

[hmm, getting negative votes for this]. Look at the question: you'll need a lot of users before this code is as slow as a database. (on current hardware, at least a few hundred thousand)

Stephan Eggermont
+2  A: 

it seems like you could use something like a bi-directional map to implement something like this. check out http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/BiMap.html for some doco.

although it doesnt give you exactly what you need in the question, its half the way there.

Chii
+2  A: 

This may be overkill for your needs, but I don't know how complex and speed sensitive your needs are, so I'll throw it out there...

Have you considered looking at an in-memory (or even local disk based like SQLite) database to handle your data. Doing so would allow you to store your data in a way that allows much more power in how you search/index your data, without many of the costs of writing your own code.

RHSeeger
+1  A: 

Do you know you really need to have a second index. You may find that a search of every user is fast enough, unless you have millions of users.

The following example takes 51 micro-second to scan 1,000 users. It takes 557 micro-seconds to scan 10,000 users.

I wouldn't suggest optimising the collection until your know whether it would make a difference.

import java.util.*;
import java.io.*;

public class TestExecutor {
    public static void main(String[] args) throws IOException {
        Map<String, User> users = new LinkedHashMap<String, User>();
        generateUsers(users, 1000, 0.1);

        // warmup.
        int count = 10000;
        for(int i=0;i< count;i++)
            getAllUsersWithInterest(users, Interest.Golf);

        long start = System.nanoTime();
        for(int i=0;i< count;i++)
            getAllUsersWithInterest(users, Interest.Golf);
        long time = System.nanoTime() - start;
        System.out.printf("Average search time %,d micro-seconds%n", time/ count/1000);
    }

    private static Set<User> getAllUsersWithInterest(Map<String, User> users, Interest golf) {
        Set<User> ret = new LinkedHashSet<User>();
        for (User user : users.values()) {
            if (user.interests.contains(golf))
                ret.add(user);
        }
        return ret;
    }

    private static void generateUsers(Map<String, User> users, int count, double interestedInGolf) {
        Random rand = new Random();
        while(users.size() < count) {
            String name = Long.toString(rand.nextLong(), 36);
            EnumSet<Interest> interests = rand.nextFloat() < interestedInGolf
                    ? EnumSet.of(Interest.Golf) : EnumSet.noneOf(Interest.class);
            users.put(name, new User(name, interests));
        }
    }

    static class User {
        private final String name;
        private final Set<Interest> interests;

        User(String name, Set<Interest> interests) {
            this.name = name;
            this.interests = interests;
        }
    }

    enum Interest {
        Golf
    }
}
Peter Lawrey
A: 

You could use 2 HashMaps. But searching only trough preferences could be complicated.

HashMap <String,Hashmap> users;

//save data
//create new user
HashMap <String,String> prefs;
//save prefs
prefs.put(pref1,value1);
prefs.put(pref2,value2);
//save user
users.put(user1,prefs);

//get data
String x = users.get(user1).get(pref1);

Maybe you don't need this solution anymore, but many people still have same problems.

kusoksna
A: 

could someone give me an example of retriving data from [hashmap>] the inner hashmap....

maheshwaran