Java HashMap проиндексирован на 2 ключа - PullRequest
4 голосов
/ 28 апреля 2009

Я хочу создать HashMap в Java для пользователей с настройками. Это было бы легко сделать в базе данных, но, к сожалению, я не могу использовать базу данных. Мне нужен способ найти пользователя по имени в HashMap и найти всех пользователей с определенным интересом (например, гольф). Если я удаляю пользователя, то все его интересы должны быть удалены.

Кто-нибудь знает хороший способ сделать эту структуру данных?

Ответы [ 8 ]

15 голосов
/ 28 апреля 2009

Я бы предложил вам создать собственную структуру данных для хранения информации. Внутри этого класса у вас может быть два HashMaps, хранящих соответствующую информацию. Затем напишите свои собственные методы для вставки и удаления пользователя.

Таким образом, вы можете контролировать операции вставки / удаления, в то же время имея возможность запрашивать каждый атрибут отдельно.

9 голосов
/ 29 апреля 2009

Знаете ли вы, что вам действительно нужно иметь второй индекс. Вы можете обнаружить, что поиск каждого пользователя достаточно быстр, если у вас нет миллионов пользователей.

В следующем примере для сканирования 1000 пользователей требуется 51 микросекунда. Для сканирования 10000 пользователей требуется 557 микросекунд.

Я бы не советовал оптимизировать коллекцию до тех пор, пока вы не узнаете, будет ли это иметь значение.

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
    }
}
6 голосов
/ 28 апреля 2009

Самое простое решение - использовать коллекцию Commons MultiKeyMap , даже если в ней отсутствуют дженерики.

... Проверьте эту тему тоже genericized-commons-collection

5 голосов
/ 28 апреля 2009

кажется, что вы могли бы использовать что-то вроде двунаправленной карты для реализации чего-то подобного. проверьте http://google -collections.googlecode.com / svn / trunk / javadoc / index.html? com / google / common / collect / BiMap.html для некоторых документов.

хотя он не дает вам именно то, что вам нужно в вопросе, он на полпути туда.

4 голосов
/ 28 апреля 2009

Это может быть излишним для ваших нужд, но я не знаю, насколько сложны и чувствительны к скорости ваши потребности, поэтому я добавлю это ...

Рассматривали ли вы просмотр базы данных в оперативной памяти (или даже на локальном диске, подобном SQLite) для обработки ваших данных. Это позволит вам хранить ваши данные таким образом, чтобы обеспечить гораздо больше возможностей при поиске / индексации ваших данных, без особых затрат на написание собственного кода.

4 голосов
/ 28 апреля 2009

Просто поместите пользователей в ArrayList и пролистайте его, пока не найдете тот, который вам нужен. Дайте каждому пользователю набор интересов. Как только вы получите достаточно пользователей, что займет слишком много времени, сортируйте их.

Как только это займет слишком много времени, взгляните на распределение интересов. Если у вас мало разных, сохраните их в растровом изображении. Если у вас ограниченный набор комбинаций интересов, храните их отдельно и предоставьте пользователю один из них.

Начните с простого, компьютеры работают быстро. Но скройте реализацию, чтобы вы могли ее изменить.

[хм, за это получают отрицательные голоса]. Посмотрите на вопрос: вам понадобится много пользователей, чтобы этот код работал так же медленно, как база данных. (на текущем оборудовании, по крайней мере, несколько сотен тысяч)

3 голосов
/ 28 апреля 2009

Я бы реализовал следующее

HashMap, который включает пользователя в качестве ключа, а значение может быть любым объектом, который включает пользовательские настройки. Пользовательские настройки могут включать список интересов, например.

И дополнительный HashMap с интересом в качестве ключа и списком пользователей, которые заинтересованы в этом.

Когда вы удаляете пользователя, вы можете получить все его интересы и удалить имя пользователя из списка HashMap по интересам. Когда список HashMap по интересам пуст, вы можете удалить интерес из HashMap.

Будьте осторожны, когда 2 или более пользователей имеют одинаковый интерес. Вы не можете удалить проценты, когда удален только один пользователь.

Недостатком является то, что у вас будет избыточная информация.

2 голосов
/ 23 сентября 2009

Вы можете использовать 2 HashMaps. Но поиск только через предпочтения может быть сложным.

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);

Возможно, вам больше не нужно это решение, но у многих людей все еще есть такие же проблемы.

...